@@ -10,7 +10,8 @@ pthread_key_t fiber_group::tlskey;
1010fiber_group::fiber_group (size_t nworkers, size_t stacksize)
1111 :nworkers(nworkers),
1212 stacksize (stacksize),
13- stop_workers(false ) {
13+ stop_workers(false ),
14+ flsdeleter(NULL ) {
1415 // initialize the thread local storage keys
1516 if (!tls_created) {
1617 pthread_key_create (&tlskey, fiber_group::tls_deleter);
@@ -24,7 +25,7 @@ fiber_group::fiber_group(size_t nworkers, size_t stacksize)
2425
2526 // launch the workers
2627 for (size_t i = 0 ;i < nworkers; ++i) {
27- workers.launch (boost::bind (&fiber_group::worker_init, this ));
28+ workers.launch (boost::bind (&fiber_group::worker_init, this , i ));
2829 }
2930}
3031
@@ -59,10 +60,12 @@ fiber_group::fiber* fiber_group::get_active_fiber() {
5960
6061
6162void fiber_group::active_queue_insert (fiber_group::fiber* value) {
62- value->next = NULL ;
63- active_tail->next = value;
64- active_tail = value;
65- ++nactive;
63+ if (value->scheduleable ) {
64+ value->next = NULL ;
65+ active_tail->next = value;
66+ active_tail = value;
67+ ++nactive;
68+ }
6669 // might want to handle the signalling mechanism here too
6770}
6871
@@ -87,14 +90,15 @@ void fiber_group::exit() {
8790 }
8891}
8992
90- void fiber_group::worker_init () {
93+ void fiber_group::worker_init (size_t workerid ) {
9194 // create a root context
9295 create_tls_ptr ();
9396 // set up the tls structure
9497 tls* t = get_tls_ptr ();
9598 t->prev_fiber = NULL ;
9699 t->cur_fiber = NULL ;
97100 t->garbage = NULL ;
101+ t->worker_id = workerid;
98102 t->parent = this ;
99103 active_lock.lock ();
100104 while (!stop_workers) {
@@ -135,12 +139,16 @@ void fiber_group::trampoline(intptr_t _args) {
135139size_t fiber_group::launch (void fn (void *), void* param) {
136140 // allocate a stack
137141 fiber* fib = new fiber;
142+ fib->parent = this ;
138143 fib->stack = malloc (stacksize);
139144 fib->id = fiber_id_counter.inc ();
140145 // VALGRIND_STACK_REGISTER(fib->stack, (char*)fib->stack + stacksize);
141- fib->tls = NULL ;
146+ fib->fls = NULL ;
142147 fib->next = NULL ;
148+ fib->deschedule_lock = NULL ;
143149 fib->terminate = false ;
150+ fib->descheduled = false ;
151+ fib->scheduleable = true ;
144152 // construct the initial context
145153 trampoline_args* args = new trampoline_args;
146154 args->fn = fn;
@@ -162,7 +170,7 @@ size_t fiber_group::launch(void fn(void*), void* param) {
162170void fiber_group::yield_to (fiber* next_fib) {
163171 // the core scheduling logic
164172 tls* t = get_tls_ptr ();
165- /*
173+ /*
166174 if (next_fib) {
167175 printf("yield to: %ld\n", next_fib->id);
168176 if (t->cur_fiber) {
@@ -186,8 +194,9 @@ void fiber_group::yield_to(fiber* next_fib) {
186194 }
187195 } else {
188196 // ok. there isn't anything to schedule to
189- // am I meant to be terminated?
190- if (t->cur_fiber && t->cur_fiber ->terminate ) {
197+ // am I meant to be terminated? or descheduled?
198+ if (t->cur_fiber &&
199+ (t->cur_fiber ->terminate || t->cur_fiber ->descheduled ) ) {
191200 // yup. killing current fiber
192201 // context switch back to basecontext which will
193202 // do the cleanup
@@ -213,25 +222,41 @@ void fiber_group::yield_to(fiber* next_fib) {
213222}
214223
215224void fiber_group::reschedule_fiber (fiber* fib) {
216- if (!fib->terminate ) {
225+ fib->lock .lock ();
226+ if (!fib->terminate && !fib->descheduled ) {
227+ fib->lock .unlock ();
217228 // we reschedule it
218229 // Re-lock the queue
219- active_lock.lock ();
220230 // printf("Reinserting %ld\n", fib->id);
231+ active_lock.lock ();
221232 active_queue_insert (fib);
222233 active_cond.signal ();
223234 active_lock.unlock ();
224- } else {
235+ } else if (fib->descheduled ) {
236+ // unflag descheduled and unset scheduleable
237+ fib->descheduled = false ;
238+ fib->scheduleable = false ;
239+ if (fib->deschedule_lock ) pthread_mutex_unlock (fib->deschedule_lock );
240+ fib->deschedule_lock = NULL ;
241+ // printf("Descheduling complete %ld\n", fib->id);
242+ fib->lock .unlock ();
243+ } else if (fib->terminate ) {
244+ fib->lock .unlock ();
225245 // previous fiber is dead. destroy it
226246 free (fib->stack );
227247 // VALGRIND_STACK_DEREGISTER(fib->stack);
248+ // delete the fiber local storage if any
249+ if (fib->fls && flsdeleter) flsdeleter (fib->fls );
228250 delete fib;
229251 // if we are out of threads, signal the join
230252 if (fibers_active.dec () == 0 ) {
231253 join_lock.lock ();
232254 join_cond.signal ();
233255 join_lock.unlock ();
234256 }
257+ } else {
258+ // impossible condition
259+ assert (false );
235260 }
236261}
237262
@@ -254,4 +279,71 @@ void fiber_group::join() {
254279 join_lock.unlock ();
255280}
256281
282+ size_t fiber_group::get_tid () {
283+ return reinterpret_cast <size_t >(get_tls_ptr ()->cur_fiber );
284+ }
285+
286+ void fiber_group::deschedule_self (pthread_mutex_t * lock) {
287+ fiber* fib = get_tls_ptr ()->cur_fiber ;
288+ fib->lock .lock ();
289+ assert (fib->descheduled == false );
290+ assert (fib->scheduleable == true );
291+ fib->deschedule_lock = lock;
292+ fib->descheduled = true ;
293+ // printf("Descheduling requested %ld\n", fib->id);
294+ fib->lock .unlock ();
295+ yield ();
296+ }
297+
298+ size_t fiber_group::get_worker_id () {
299+ fiber_group::tls* tls = get_tls_ptr ();
300+ return tls->worker_id ;
301+ }
302+
303+ void fiber_group::schedule_tid (size_t tid) {
304+ fiber* fib = reinterpret_cast <fiber*>(tid);
305+ fib->lock .lock ();
306+ // we MUST get here only after the thread was completely descheduled
307+ // or no deschedule operation has happened yet.
308+ assert (fib->descheduled == false );
309+ fib->descheduled = false ;
310+ if (fib->scheduleable == false ) {
311+ // if this thread was descheduled completely. Reschedule it.
312+ // printf("Scheduling requested %ld\n", fib->id);
313+ fib->scheduleable = true ;
314+ fib->lock .unlock ();
315+ fib->parent ->reschedule_fiber (fib);
316+ } else {
317+ // printf("Scheduling requested of running thread %ld\n", fib->id);
318+ fib->lock .unlock ();
319+ }
320+ }
321+
322+
323+ void fiber_group::set_tls_deleter (void (*deleter)(void *)) {
324+ flsdeleter = deleter;
325+ }
326+
327+ void * fiber_group::get_tls () {
328+ fiber_group::tls* f = get_tls_ptr ();
329+ if (f != NULL ) {
330+ return f->cur_fiber ->fls ;
331+ } else {
332+ // cannot get TLS of a non-fiber
333+ assert (false );
334+ return NULL ;
335+ }
336+ }
337+
338+ void fiber_group::set_tls (void * tls) {
339+ fiber_group::tls* f = get_tls_ptr ();
340+ if (f != NULL ) {
341+ f->cur_fiber ->fls = tls;
342+ } else {
343+ // cannot get TLS of a non-fiber
344+ assert (false );
345+ }
346+ }
347+
348+
257349}
0 commit comments