📄 pthread.c
字号:
/** Cleanup thread on asynchronous exit. * @param buffer a pointer to a stack allocated cleanup buffer. * @param routine the cleanup routine. * @param arg an argument for the cleanup routine. * * This is a replacement for the internal glibc function * _pthread_cleanup_push_defer(). The function is declared in <pthread.h> as a * weak undefined symbol in glibc to allow the pthreads library to override the * function. The struct _pthread_cleanup_buffer structure is also declared in * <pthread.h>. */void_pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *buffer, void (*routine) (void *), void *arg){ /** If the weak undefined symbol, __pthread_cleanup_push_defer() is * loaded, a suitable threads library exists, and the library symbol is * called. */ if (__pthread_cleanup_push_defer) return __pthread_cleanup_push_defer(buffer, routine, arg); /** Otherwise, The function must initialize the cleanup buffer pointed * to by buffer that was pushed onto the stack by glibc as well as * setting the cancellation type for the current thread to deferred and * storing the previous thread cancellation state into the supplied * buffer. */ buffer->__routine = routine; buffer->__arg = arg; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &buffer->__canceltype); buffer->__prev = NULL;}/** Cleanup thread on asynchronous exit. * @param buffer a pointer to a stack allocated cleanup buffer. * @param execute whether to execute the cleanup function. * * This is a replacement for the internal glibc function * _pthread_cleanup_pop(). The function is declared in <pthread.h> as a weak * undefined symbol in glibc to allow the pthreads library to override the * function. The struct _pthread_cleanup_buffer structure is also declared in * <pthread.h>. */void_pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *buffer, int execute){ /** If the weak undefined symbol, __pthread_cleanup_pop_restore() is * loaded, a suitable threads library exists, and the library symbol is * called. */ if (__pthread_cleanup_pop_restore) return __pthread_cleanup_pop_restore(buffer, execute); /** Otherwise, function must deinitialize the cleanup buffer pointerd to * by buffer that will be popped from the stack by glibc, as well a * setting the thread cancellation type back to the previous value from * buffer. */ if (execute) (*buffer->__routine) (buffer->__arg); pthread_setcanceltype(buffer->__canceltype, NULL);}/** Test for asyncrhonous thread cancellation (while deferred). * This is a non-recursive replacement for the pthread library function, pthread_testcancel(3). */voidpthread_testcancel(void){ /** If the weak undefined symbol, __pthread_testcancel() is loaded, a * suitable threads library exists and the library symbol is called. */ if (__pthread_testcancel) return __pthread_testcancel(); /** Otherwise, for non-threaded operation, this is a noop. */ return;}/** Thread cancellation type storage. * @internal This is a statically allocated internal storage for holding the * thread cancellation type when no suitable threads library is loaded * (non-thread-safe operation). */static int __pthread_canceltype = 0;/** Set or defer thread asynchronous cancellation. * @param type cancellation type to set. * @param oldtype place to return current type. * * This is a non-recursive replacement for the pthread library function, pthread_setcanceltype(3). */intpthread_setcanceltype(int type, int *oldtype){ /** If the weak undefined symbol, __pthread_setcanceltype() is loaded, a suitable threads * library exists, and the library symbol is called. */ if (__pthread_setcanceltype) return __pthread_setcanceltype(type, oldtype); /** Otherwise, for non-thread operation, this function simply saves new * type and returns the oldtype from a static variable. One of the * ramifications of this is that the cancel type might not be correct * after a fork(2). */ if (oldtype != NULL) *oldtype = __pthread_canceltype; __pthread_canceltype = type; return (0); /** @return Returns zero (0) on success, error number on failure. */}/** Initialize a reader/writer lock. * @param rwlock the lock to initalize. * @param attr a pointer to lock attributes. * * This is a non-recursive replacement for the pthread library function, * pthread_rwlock_init(3). */intpthread_rwlock_init(pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attr){ /** If the weak undefined symbol, __pthread_rwlock_init(), is loaded, a * suitable threads library exists, and the library symbol is called. */ if (__pthread_rwlock_init) return __pthread_rwlock_init(rwlock, attr); /** Otherwise, for non-threaded operation, this function simply * initializes the first byte of the lock structure to zero to indicate * that the lock is unlocked. */ *(char *) rwlock = 0; return (0); /** @return Returns zero (0) on success, error number on failure. */}/** Read-lock a reader/writer lock. * @param rwlock the lock to read lock. * * This is a non-recursive replacement for the pthread library function, * pthread_rwlock_rdlock(3). */intpthread_rwlock_rdlock(pthread_rwlock_t * rwlock){ /** If the weak undefined symbol, __pthread_rwlock_rdlock(), is loaded, * a suitablel threads library exists, and the library symbol is * called. */ if (__pthread_rwlock_rdlock) return __pthread_rwlock_rdlock(rwlock); /** Otherwise, for non-threaded operation, this function simply * increments the first by of the lock structure (POSIX locks are * recursive in that multiple reader locks can be taken by the same * thread). */ *(char *) rwlock = *(char *) rwlock + 1; return (0); /** @return Returns zero (0) on success, error number on failure. */}/** Write-lock a reader/writer lock. * @param rwlock the lock to write lock. * * This is a non-recursive replacement for the pthread library function, pthread_rwlock_wrlock(3). * */intpthread_rwlock_wrlock(pthread_rwlock_t * rwlock){ /** If the weak undefined symbol, __pthread_rwlock_wrlock(), is loaded, * a suitable threads library exists, and the library symbol is called. */ if (__pthread_rwlock_wrlock) return __pthread_rwlock_wrlock(rwlock); /** Otherwise, the first byte of the lock structus is imply decremented * (although POSIX locks cannot recurse on write). Note that if the * byte is not zero, then it is an errror that can be detected here. * If debugging, print an error message. */ if (*(char *) rwlock != 0) { errno = EDEADLK;#ifdef DEBUG perror(__FUNCTION__);#endif return (errno); } *(char *) rwlock = *(char *) rwlock - 1; return (0); /** @return Returns zero (0) on success, error number on failure. */ /** @retval EDEADLK Attempting to lock would cause a deadlock. */}/** Unlock a reader/writer lock. * This is a non-recursive replacement for the pthread library function, * pthread_rwlock_unlock(3). */intpthread_rwlock_unlock(pthread_rwlock_t * rwlock){ /** If the weak undefined symbol, __pthread_rwlock_unlock(), is loaded, * a suitable threads library exists, and the library symbol is called. * */ if (__pthread_rwlock_unlock) return __pthread_rwlock_unlock(rwlock); /** Otherwise, if the value of the first byte is greater than zero (read * locked), decrement the value; minus one (-1) (write locked), set it * to zero. Note that if the byte is already set to zero, the lock is * unlocked. If debugging, print an error message. */ if (*(char *) rwlock == -2 || *(char *)rwlock == 0) {#ifdef DEBUG errno = EINVAL; perror(__FUNCTION__);#endif return (EINVAL); } if (*(char *) rwlock > 0) *(char *) rwlock = *(char *) rwlock - 1; else *(char *) rwlock = 0; return (0); /** @return Returns zero (0) on success, error number on failure. */}/** Destroy a reader/writer lock. * This is a non-recursive replacement for the pthread library function, * pthread_rwlock_destroy(3). */intpthread_rwlock_destroy(pthread_rwlock_t * rwlock){ /** If the weak undefined symbol, __pthread_rwlock_destroy(), is loaded, * a suitable threads library exists, and the library symbol is called. */ if (__pthread_rwlock_destroy) return __pthread_rwlock_destroy(rwlock); /** Otherwise, just set it to some illegal value. */ *(char *) rwlock = -2; return (0); /** @return Returns zero (0) on success, error number on failure. */}/** Perform a procedure once for all threads. * This is a non-recursive replacement for the pthread library function, * pthread_once(3). */intpthread_once(pthread_once_t * once_control, void (*init_routine) (void)){ /** If the weak undefined symbol, __pthread_once(), is loaded, a * suitable threads library exists, and the library symbol is called. */ if (__pthread_once) return __pthread_once(once_control, init_routine); /** Otherwise, if the value of the control is zero, set it to one and * call the init routine. */ if (*once_control == 0) { *once_control = 1; init_routine(); } return (0); /** @return Always returns zero (0). */}/** Key retention structure. */struct __pthread_key_data { int exists; /**< True when created, false when available. */ void *value; /**< Value if it exists. */};/** Array of thread-specific-data keys. */static struct __pthread_key_data ___pthread_keys[PTHREAD_KEYS_MAX] = { { 0, }, };/** Create a thread-specific data key. * This is a non-recursive replacement for the pthread library function, * pthread_key_create(3). */intpthread_key_create(pthread_key_t * key, void (*destr_function) (void *)){ int i; /** If the weak undefined symbol, __pthread_key_create(), is loaded, a * suitable threads library exists, and the library symbol is called. */ if (__pthread_key_create) return __pthread_key_create(key, destr_function); /** Otherwise, allocate a new key from the statically allocated keys * structure and null its value. */ for (i = 0; i < PTHREAD_KEYS_MAX; i++) if (!___pthread_keys[i].exists) break; if (i == PTHREAD_KEYS_MAX) return (ENOMEM); ___pthread_keys[i].exists = 1; ___pthread_keys[i].value = NULL; *key = i; return (0); /** @return Returns zero (0) on success, error number on failure. On * success, the key value is stored in the area pointed to by argument * key. */ /** @retval ENOMEM No keys left. */}/** Set a thread-specific data value. * This is a non-recursive replacement for the pthread library function, * pthread_setspecific(3). */intpthread_setspecific(pthread_key_t key, const void *pointer){ /** If the weak undefined symbol, __pthread_setspecific(), is loaded, a * suitable threads library exists, and the library symbol is called. */ if (__pthread_setspecific) return __pthread_setspecific(key, pointer); /** Otherwise, set the value in the statically allocated array. */ if (key < 0 || key >= PTHREAD_KEYS_MAX || !___pthread_keys[key].exists) return (EINVAL); ___pthread_keys[key].value = (void *) pointer; return (0); /** @return Returns zero (0) on success, error number on * failure. On success, the thread specific data pointer * specified by argument key is set to the value of argument * pointer. */ /** @retval EINVAL Invalid key argument. */}/** Set a thread-specific data value. * This is a non-recursive replacement for the pthread library function, * pthread_getspecific(3). */void *pthread_getspecific(pthread_key_t key){ /** If the weak undefined symbol, __pthread_getspecific(), is loaded, a * suitable threads library exists, and the library symbol is called. */ if (__pthread_getspecific) return __pthread_getspecific(key); /** Otherwise, get the value from the statically allocated array. */ if (key < 0 || key >= PTHREAD_KEYS_MAX || !___pthread_keys[key].exists) { errno = EINVAL; return (NULL); } return ___pthread_keys[key].value; /** @return On success, returns the thread specific data associated with * argument key; on failure, returns NULL. */ /** @retval EINVAL Invalid key argument. */}/** Delete a thread-specific data key. * This is a non-recursive replacement for the pthread library function, * pthread_key_delete(3). */intpthread_key_delete(pthread_key_t key){ /** If the weak undefined symbol, __pthread_key_delete(), is loaded, a * suitable threads library exists, and the library symbol is called. */ if (__pthread_key_delete) return __pthread_key_delete(key); /* Otherwise, mark the key available in the statically allocated array. */ if (key < 0 || key >= PTHREAD_KEYS_MAX || !___pthread_keys[key].exists) return (EINVAL); ___pthread_keys[key].exists = 0; ___pthread_keys[key].value = NULL; return (0); /** @return Returns zero (0) on success, error number on failure. */ /** @retval EINVAL Invalid key argument. */}/** @} */// vim: ft=c com=sr\:/**,mb\:\ *,eb\:\ */,sr\:/*,mb\:*,eb\:*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -