static void* ccr_worker(void *arg) { int r, resume; process_t *proc; while (1) { // Checks if threads need to be killed and the the ready procces's queue is empty // That way only when the queue is empty the threads are killed // if ((free_flag.compare_and_swap(false, true)) && (prc_ready.empty())) if (free_flag.compare_and_swap(false, true)) { pthread_t thread = pthread_self(); // removes reference from the pool thr_pool.remove(thread); // checks if threre's more threads to kill and set the flag if (free_workers.fetch_and_decrement() > 1) { free_flag.compare_and_swap(true, false); } //kills the current thread pthread_exit(NULL); } prc_ready.pop(proc); if (!proc) return NULL; r = lua_resume(proc->L, 0); switch (r) { case LUA_YIELD: //cerr << "Yield!\n"; switch (proc->status) { case PS_READY: // releasing the lock acquired in ccr_yield proc->wlock.release(); prc_ready.push(proc); break; case PS_BLOCKING: proc->status = PS_BLOCKED; // releasing the lock acquired in ccr_yield proc->wlock.release(); break; } break; case LUA_ERRRUN: case LUA_ERRMEM: case LUA_ERRERR: cerr << "[ERROR][PROCESSING A LUA PROCESS] " << lua_tostring(proc->L, -1) << endl; // fall-through case 0: lua_close(proc->L); mbx_close(proc->mbox); prc_free(proc); break; } } return NULL; }
void private_server::wake_some( int additional_slack ) { __TBB_ASSERT( additional_slack>=0, NULL ); private_worker* wakee[2]; private_worker**w = wakee; { tbb::spin_mutex::scoped_lock lock(my_asleep_list_mutex); while( my_asleep_list_root && w<wakee+2 ) { if( additional_slack>0 ) { --additional_slack; } else { // Try to claim unit of slack int old; do { old = my_slack; if( old<=0 ) goto done; } while( my_slack.compare_and_swap(old-1,old)!=old ); } // Pop sleeping worker to combine with claimed unit of slack my_asleep_list_root = (*w++ = my_asleep_list_root)->my_next; } if( additional_slack ) { // Contribute our unused slack to my_slack. my_slack += additional_slack; } } done: while( w>wakee ) (*--w)->my_thread_monitor.notify(); }
void private_worker::run() { if( my_state.compare_and_swap( st_normal, st_init )==st_init ) { ::rml::job& j = *my_client.create_one_job(); --my_server.my_slack; while( my_state==st_normal ) { if( my_server.my_slack>=0 ) { my_client.process(j); } else { thread_monitor::cookie c; // Prepare to wait my_thread_monitor.prepare_wait(c); // Check/set the invariant for sleeping if( my_state==st_normal && my_server.try_insert_in_asleep_list(*this) ) { my_thread_monitor.commit_wait(c); // Propagate chain reaction if( my_server.has_sleepers() ) my_server.wake_some(0); } else { // Invariant broken my_thread_monitor.cancel_wait(); } } } my_client.cleanup(j); ++my_server.my_slack; } my_server.remove_server_ref(); }
void operator()( int i ) const { internal::concurrent_monitor::thread_context thr_ctx; if( i==0 ) { size_t n_expected_sleepers = NTHRS_USED_IN_DESTRUCTOR_TEST-1; while( n_sleepers<n_expected_sleepers ) __TBB_Yield(); while( n_sleepers.compare_and_swap( VLN+NTHRS_USED_IN_DESTRUCTOR_TEST, n_expected_sleepers )!=n_expected_sleepers ) __TBB_Yield(); for( int j=0; j<100; ++j ) Harness::Sleep( 1 ); delete mon; mon = NULL; } else { mon->prepare_wait( thr_ctx, uintptr_t(this) ); while( n_sleepers<VLN ) { try { ++n_sleepers; mon->commit_wait( thr_ctx ); if( --n_sleepers>VLN ) break; } catch( tbb::user_abort& ) { // can no longer access 'mon' break; } mon->prepare_wait( thr_ctx, uintptr_t(this) ); } } }
// Perform an atomic bitwise-AND on the operand, and return its previous value. inline uintptr_t fetch_and_and(atomic<uintptr_t>& operand, uintptr_t value) { for (tbb::internal::atomic_backoff b;;b.pause()) { uintptr_t old = operand; uintptr_t result = operand.compare_and_swap(old&value, old); if (result==old) return result; } }
// Finalizes a worker thread static int ccr_dec_workers(lua_State *L) { int count = (int)luaL_checkinteger(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, CCR_SELF); process_t *proc = (process_t*)lua_touserdata(L, -1); // checks if the calling process is a main process if(proc->main) { if (thr_pool.size() - count < THR_SIZE) { lua_pushinteger(L, 0); lua_pushstring(L, "thread pool is already at the minimum size"); return 2; } // sets the numbers threads to kill free_workers.fetch_and_add(count); // sets the flag indication to kill threads free_flag.compare_and_swap(true, false); // returns the current number of threads in the pool lua_pushinteger(L, (lua_Integer) thr_pool.size() - count); return 1; } lua_pushinteger(L, 0); lua_pushstring(L, "only a main process could free threads"); return 2; }
void private_worker::start_shutdown() { state_t s; // Transition from st_init or st_normal to st_plugged or st_quit do { s = my_state; __TBB_ASSERT( s==st_init||s==st_normal, NULL ); } while( my_state.compare_and_swap( s==st_init? st_plugged : st_quit, s )!=s ); if( s==st_normal ) { // May have invalidated invariant for sleeping, so wake up the thread. // Note that the notify() here occurs without maintaining invariants for my_slack. // It does not matter, because my_state==st_quit overrides checking of my_slack. my_thread_monitor.notify(); } }