📄 timer_routines.c
字号:
/* Helper code for POSIX timer implementation on NPTL. Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <assert.h>#include <errno.h>#include <pthread.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <sysdep.h>#include <time.h>#include <unistd.h>#include <sys/syscall.h>#include "posix-timer.h"#include <pthreadP.h>/* Number of threads used. */#define THREAD_MAXNODES 16/* Array containing the descriptors for the used threads. */static struct thread_node thread_array[THREAD_MAXNODES];/* Static array with the structures for all the timers. */struct timer_node __timer_array[TIMER_MAX];/* Global lock to protect operation on the lists. */pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;/* Variable to protext initialization. */pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;/* Nonzero if initialization of timer implementation failed. */int __timer_init_failed;/* Node for the thread used to deliver signals. */struct thread_node __timer_signal_thread_rclk;/* Lists to keep free and used timers and threads. */struct list_links timer_free_list;struct list_links thread_free_list;struct list_links thread_active_list;#ifdef __NR_rt_sigqueueinfoextern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *);#endif/* List handling functions. */static inline voidlist_init (struct list_links *list){ list->next = list->prev = list;}static inline voidlist_append (struct list_links *list, struct list_links *newp){ newp->prev = list->prev; newp->next = list; list->prev->next = newp; list->prev = newp;}static inline voidlist_insbefore (struct list_links *list, struct list_links *newp){ list_append (list, newp);}/* * Like list_unlink_ip, except that calling it on a node that * is already unlinked is disastrous rather than a noop. */static inline voidlist_unlink (struct list_links *list){ struct list_links *lnext = list->next, *lprev = list->prev; lnext->prev = lprev; lprev->next = lnext;}static inline struct list_links *list_first (struct list_links *list){ return list->next;}static inline struct list_links *list_null (struct list_links *list){ return list;}static inline struct list_links *list_next (struct list_links *list){ return list->next;}static inline intlist_isempty (struct list_links *list){ return list->next == list;}/* Functions build on top of the list functions. */static inline struct thread_node *thread_links2ptr (struct list_links *list){ return (struct thread_node *) ((char *) list - offsetof (struct thread_node, links));}static inline struct timer_node *timer_links2ptr (struct list_links *list){ return (struct timer_node *) ((char *) list - offsetof (struct timer_node, links));}/* Initialize a newly allocated thread structure. */static voidthread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id){ if (attr != NULL) thread->attr = *attr; else { pthread_attr_init (&thread->attr); pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED); } thread->exists = 0; list_init (&thread->timer_queue); pthread_cond_init (&thread->cond, 0); thread->current_timer = 0; thread->captured = pthread_self (); thread->clock_id = clock_id;}/* Initialize the global lists, and acquire global resources. Error reporting is done by storing a non-zero value to the global variable timer_init_failed. */static voidinit_module (void){ int i; list_init (&timer_free_list); list_init (&thread_free_list); list_init (&thread_active_list); for (i = 0; i < TIMER_MAX; ++i) { list_append (&timer_free_list, &__timer_array[i].links); __timer_array[i].inuse = TIMER_FREE; } for (i = 0; i < THREAD_MAXNODES; ++i) list_append (&thread_free_list, &thread_array[i].links); thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);}/* This is a handler executed in a child process after a fork() occurs. It reinitializes the module, resetting all of the data structures to their initial state. The mutex is initialized in case it was locked in the parent process. */static voidreinit_after_fork (void){ init_module (); pthread_mutex_init (&__timer_mutex, 0);}/* Called once form pthread_once in timer_init. This initializes the module and ensures that reinit_after_fork will be executed in any child process. */void__timer_init_once (void){ init_module (); pthread_atfork (0, 0, reinit_after_fork);}/* Deinitialize a thread that is about to be deallocated. */static voidthread_deinit (struct thread_node *thread){ assert (list_isempty (&thread->timer_queue)); pthread_cond_destroy (&thread->cond);}/* Allocate a thread structure from the global free list. Global mutex lock must be held by caller. The thread is moved to the active list. */struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id){ struct list_links *node = list_first (&thread_free_list); if (node != list_null (&thread_free_list)) { struct thread_node *thread = thread_links2ptr (node); list_unlink (node); thread_init (thread, desired_attr, clock_id); list_append (&thread_active_list, node); return thread; } return 0;}/* Return a thread structure to the global free list. Global lock must be held by caller. */void__timer_thread_dealloc (struct thread_node *thread){ thread_deinit (thread); list_unlink (&thread->links); list_append (&thread_free_list, &thread->links);}/* Each of our threads which terminates executes this cleanup handler. We never terminate threads ourselves; if a thread gets here it means that the evil application has killed it. If the thread has timers, these require servicing and so we must hire a replacement thread right away. We must also unblock another thread that may have been waiting for this thread to finish servicing a timer (see timer_delete()). */static voidthread_cleanup (void *val){ if (val != NULL) { struct thread_node *thread = val; /* How did the signal thread get killed? */ assert (thread != &__timer_signal_thread_rclk); pthread_mutex_lock (&__timer_mutex); thread->exists = 0; /* We are no longer processing a timer event. */ thread->current_timer = 0; if (list_isempty (&thread->timer_queue)) __timer_thread_dealloc (thread); else (void) __timer_thread_start (thread); pthread_mutex_unlock (&__timer_mutex); /* Unblock potentially blocked timer_delete(). */ pthread_cond_broadcast (&thread->cond); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -