// Run once static BOOL CALLBACK __offload_run_once_wrapper( PINIT_ONCE initOnce, PVOID parameter, PVOID *context ) { void (*init_routine)(void) = (void(*)(void)) parameter; init_routine(); return true; }
/* This implements pthread_once() for the single-threaded case. */ static int _libc_once(pthread_once_t *once_control, void (*init_routine)(void)) { if (once_control->state == PTHREAD_DONE_INIT) return (0); init_routine(); once_control->state = PTHREAD_DONE_INIT; return (0); }
int __pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) { for (;;) { int oldval; int newval; /* Pseudo code: newval = __fork_generation | 1; oldval = *once_control; if ((oldval & 2) == 0) *once_control = newval; Do this atomically. */ do { newval = __fork_generation | 1; oldval = *once_control; if (oldval & 2) break; } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval); /* Check if the initializer has already been done. */ if ((oldval & 2) != 0) return 0; /* Check if another thread already runs the initializer. */ if ((oldval & 1) == 0) break; /* Check whether the initializer execution was interrupted by a fork. */ if (oldval != newval) break; /* Same generation, some other thread was faster. Wait. */ lll_futex_wait (once_control, oldval, LLL_PRIVATE); } /* This thread is the first here. Do the initialization. Register a cleanup handler so that in case the thread gets interrupted the initialization can be restarted. */ pthread_cleanup_push (clear_once_control, once_control); init_routine (); pthread_cleanup_pop (0); /* Say that the initialisation is done. */ *once_control = __fork_generation | 2; /* Wake up all other threads. */ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); return 0; }
int pthread_once( pthread_once_t *once_control, void (*init_routine)(void)) { pthread_initialize(); if (once_control == NULL || init_routine == NULL) return_errno(EINVAL, EINVAL); if (*once_control != 1) init_routine(); *once_control = 1; return OK; }
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { BOOL pending; if (!InitOnceBeginInitialize(once_control, 0, &pending, NULL)) abort(); if (pending) { init_routine(); InitOnceComplete(once_control, 0, NULL); } return 0; }
/** * Once-only initialization. * @param once_control The control variable which initialized to PTHREAD_ONCE_INIT. * @param init_routine The initialization code which executed at most once. * @return Always return 0. */ int pthread_once(pthread_once_t *once_control, void (* init_routine)(void)) { if (atomic_cmpxchg((long volatile *) once_control, 1, 0) == 0) { init_routine(); *(volatile int *) once_control = 2; } else { while(*(volatile int *) once_control != 2) SwitchToThread(); } return 0; }
/* * __wt_init_once_callback -- * Global initialization, run once. */ BOOL CALLBACK _wt_init_once_callback( _Inout_ PINIT_ONCE InitOnce, _Inout_opt_ PVOID Parameter, _Out_opt_ PVOID *Context ) { void(*init_routine)(void) = Parameter; init_routine(); return (TRUE); }
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { if (PTHREAD_ONCE_INIT == *once_control) { pthread_mutex_lock(&once_mutex); if (PTHREAD_ONCE_INIT == *once_control) { init_routine(); *once_control = 42; } pthread_mutex_unlock(&once_mutex); } return 0; }
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { if(compare_and_swap((void *)once_control, (void *)0, (void *)1)) init_routine(); //TODO: "The pthread_once() function is not a cancellation point. //However, if init_routine is a cancellation point and is canceled, //the effect on once_control shall be as if pthread_once() was never called." //TODO: "The pthread_once() function may fail if: //[EINVAL] // If either once_control or init_routine is invalid. (Question: what does 'invalid' mean?) return 0; }
int acl_pthread_once(acl_pthread_once_t *once_control, void (*init_routine)(void)) { int n = 0; if (once_control == NULL || init_routine == NULL) { acl_set_error(ACL_EINVAL); return ACL_EINVAL; } /* 只有第一个调用 InterlockedCompareExchange 的线程才会执行 * init_routine, 后续线程永远在 InterlockedCompareExchange * 外运行,并且一直进入空循环直至第一个线程执行 init_routine * 完毕并且将 *once_control 重新赋值, 只有在多核环境中多个线程 * 同时运行至此时才有可能出现短暂的后续线程空循环现象,如果 * 多个线程顺序至此,则因为 *once_control 已经被第一个线程重新 * 赋值而不会进入循环体内只所以如此处理,是为了保证所有线程在 * 调用 acl_pthread_once 返回前 init_routine 必须被调用且仅能 * 被调用一次, 但在VC6下,InterlockedCompareExchange 接口定义 * 有些怪异,需要做硬性指定参数类型,参见 <Windows 高级编程指南> * Jeffrey Richter, 366 页 */ while (1) { #ifdef MS_VC6 LONG prev = InterlockedCompareExchange((PVOID) once_control, (PVOID) 1, (PVOID) ACL_PTHREAD_ONCE_INIT); #else LONG prev = InterlockedCompareExchange( once_control, 1, ACL_PTHREAD_ONCE_INIT); #endif if (prev == 2) return 0; else if (prev == 0) { /* 只有第一个线程才会至此 */ init_routine(); /* 将 *conce_control 重新赋值以使后续线程不进入 while * 循环或从 while 循环中跳出 */ InterlockedExchange(once_control, 2); return 0; } else { acl_assert(prev == 1); /* 防止空循环过多地浪费CPU */ Sleep(1); /** sleep 1ms */ } } return 1; /* 不可达代码,避免编译器报警告 */ }
void thread_once(thread_once_t *once_control, void (*init_routine)(void)) { #ifdef WIN32 while (InterlockedExchange(&(once_control->lock), 1) != 0) { Sleep(1); } if (!once_control->state) { once_control->state = 1; init_routine(); } InterlockedExchange(&(once_control->lock), 0); #else pthread_once(once_control, init_routine); #endif }
int _pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) { if (once_control->state == PTHREAD_NEEDS_INIT) { if (_thread_initial == NULL) _thread_init(); _pthread_mutex_lock(&(once_control->mutex)); if (once_control->state == PTHREAD_NEEDS_INIT) { init_routine(); once_control->state = PTHREAD_DONE_INIT; } _pthread_mutex_unlock(&(once_control->mutex)); } return (0); }
int UC_posix_class::uc_pthread_once(uc_pthread_once_t *once_control, void (*init_routine)(void)){ if (once_control == NULL) { return -1; } if (init_routine == NULL) { return -1; } if (*once_control) { init_routine(); } (*once_control) = 0; return 0; }
int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) { int ret; if (once_control->state == PTHREAD_NEEDS_INIT) { if ((ret = pthread_mutex_lock(&(once_control->mutex))) != 0) return ret; if (once_control->state == PTHREAD_NEEDS_INIT) { init_routine(); once_control->state = PTHREAD_DONE_INIT; } pthread_mutex_unlock(&(once_control->mutex)); } return (0); }
int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) { /* flag for doing the condition broadcast outside of mutex */ int state_changed; /* Test without locking first for speed */ if (*once_control == DONE) { READ_MEMORY_BARRIER(); return 0; } /* Lock and test again */ state_changed = 0; pthread_mutex_lock(&once_masterlock); /* If this object was left in an IN_PROGRESS state in a parent process (indicated by stale generation field), reset it to NEVER. */ if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation) *once_control = NEVER; /* If init_routine is being called from another routine, wait until it completes. */ while ((*once_control & 3) == IN_PROGRESS) { pthread_cond_wait(&once_finished, &once_masterlock); } /* Here *once_control is stable and either NEVER or DONE. */ if (*once_control == NEVER) { *once_control = IN_PROGRESS | fork_generation; pthread_mutex_unlock(&once_masterlock); pthread_cleanup_push(pthread_once_cancelhandler, once_control); init_routine(); pthread_cleanup_pop(0); pthread_mutex_lock(&once_masterlock); WRITE_MEMORY_BARRIER(); *once_control = DONE; state_changed = 1; } pthread_mutex_unlock(&once_masterlock); if (state_changed) pthread_cond_broadcast(&once_finished); return 0; }
int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) { RT_ASSERT(once_control != RT_NULL); RT_ASSERT(init_routine != RT_NULL); rt_enter_critical(); if (!(*once_control)) { /* call routine once */ *once_control = 1; rt_exit_critical(); init_routine(); } rt_exit_critical(); return 0; }
int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { int ret; if((ret = pthread_mutex_lock(&once_control->__mutex)) != EOK) { return (once_control->__once != 0) ? EOK : ret; } if( once_control->__once == 0 ) { pthread_cleanup_push(pthread_once_cancel, &once_control->__mutex); init_routine(); pthread_cleanup_pop(0); once_control->__once = 1; } if(pthread_mutex_unlock(&once_control->__mutex) == EOK) { pthread_mutex_destroy(&once_control->__mutex); } return EOK; }
/* * Call the given routine once, and only once. tsocks_once returning * guarantees that the routine has succeded. */ void tsocks_once(tsocks_once_t *o, void (*init_routine)(void)) { /* Why, yes, pthread_once(3P) exists. Said routine requires linking in a * real pthread library on Linux, while this does not and will do the right * thing even with the stub implementation. */ assert(o); /* This looks scary and incorrect, till you realize that the * pthread_mutex routines include memory barriers. */ if (!o->once) { return; } tsocks_mutex_lock(&o->mutex); if (o->once) { init_routine(); o->once = 0; } tsocks_mutex_unlock(&o->mutex); }
/** * Execute an initialization routine. * * This service may be used by libraries which need an initialization function * to be called only once. * * The function @a init_routine will only be called, with no argument, the first * time this service is called specifying the address @a once. * * @return 0 on success; * @return an error number if: * - EINVAL, the object pointed to by @a once is invalid (it must have been * initialized with PTHREAD_ONCE_INIT). * * @see * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_once.html"> * Specification.</a> * */ int pthread_once(pthread_once_t * once, void (*init_routine) (void)) { spl_t s; xnlock_get_irqsave(&nklock, s); if (!pse51_obj_active(once, PSE51_ONCE_MAGIC, pthread_once_t)) { xnlock_put_irqrestore(&nklock, s); return EINVAL; } if (!once->routine_called) { init_routine(); /* If the calling thread is canceled while executing init_routine, routine_called will not be set to 1. */ once->routine_called = 1; } xnlock_put_irqrestore(&nklock, s); return 0; }
VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control, void (*init_routine)(void)) { /* In order to be thread-safe we need to re-test *once_control * inside the lock. The outer test is basically an optimization * so that once it is initialized we don't need to waste time * trying to acquire the lock. */ if ( *once_control == 0 ) { vcos_global_lock(); if ( *once_control == 0 ) { init_routine(); *once_control = 1; } vcos_global_unlock(); } return VCOS_SUCCESS; }
// This implementation doesn't support thread-cancelation nor fork during // the execution of init_routine(). int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { // pthread_once always returns 0. if (once_control == NULL || init_routine == NULL) { return 0; } // Double-checked locking is not a good solution in general, but it works // in this case in C. if (*once_control != PTHREAD_ONCE_INIT) { return 0; } pthread_mutex_lock(&once_lock); if (*once_control == PTHREAD_ONCE_INIT) { init_routine(); *once_control = PTHREAD_ONCE_INIT + 1; } pthread_mutex_unlock(&once_lock); return 0; }
int pthread_once(pthread_once_t* once_control, void (*init_routine)(void)) { if(atomic_swap(once_control,1) == 0) init_routine(); return 0; }
int pthread_once(pthread_once_t* once, void (*init_routine)()) { if(cpu_CAS((volatile intptr_t*)once, 0, 1)) init_routine(); return 0; }
__pthread_once_slow (pthread_once_t *once_control, void (*init_routine) (void)) { while (1) { int val, newval; /* We need acquire memory order for this load because if the value signals that initialization has finished, we need to see any data modifications done during initialization. */ val = atomic_load_acquire (once_control); do { /* Check if the initialization has already been done. */ if (__glibc_likely ((val & __PTHREAD_ONCE_DONE) != 0)) return 0; /* We try to set the state to in-progress and having the current fork generation. We don't need atomic accesses for the fork generation because it's immutable in a particular process, and forked child processes start with a single thread that modified the generation. */ newval = __fork_generation | __PTHREAD_ONCE_INPROGRESS; /* We need acquire memory order here for the same reason as for the load from once_control above. */ } while (__glibc_unlikely (!atomic_compare_exchange_weak_acquire ( once_control, &val, newval))); /* Check if another thread already runs the initializer. */ if ((val & __PTHREAD_ONCE_INPROGRESS) != 0) { /* Check whether the initializer execution was interrupted by a fork. We know that for both values, __PTHREAD_ONCE_INPROGRESS is set and __PTHREAD_ONCE_DONE is not. */ if (val == newval) { /* Same generation, some other thread was faster. Wait and retry. */ futex_wait_simple ((unsigned int *) once_control, (unsigned int) newval, FUTEX_PRIVATE); continue; } } /* This thread is the first here. Do the initialization. Register a cleanup handler so that in case the thread gets interrupted the initialization can be restarted. */ pthread_cleanup_push (clear_once_control, once_control); init_routine (); pthread_cleanup_pop (0); /* Mark *once_control as having finished the initialization. We need release memory order here because we need to synchronize with other threads that want to use the initialized data. */ atomic_store_release (once_control, __PTHREAD_ONCE_DONE); /* Wake up all other threads. */ futex_wake ((unsigned int *) once_control, INT_MAX, FUTEX_PRIVATE); break; } return 0; }