1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <pthread.h>
32 #include <signal.h>
33 #include <sched.h>
34 
35 #include <sys/time.h>
36 #include <sys/resource.h>
37 
38 #include <direct/debug.h>
39 #include <direct/list.h>
40 #include <direct/mem.h>
41 #include <direct/messages.h>
42 #include <direct/signals.h>
43 #include <direct/system.h>
44 #include <direct/thread.h>
45 #include <direct/util.h>
46 
47 D_DEBUG_DOMAIN( Direct_Thread,     "Direct/Thread",      "Thread management" );
48 D_DEBUG_DOMAIN( Direct_ThreadInit, "Direct/Thread/Init", "Thread initialization" );
49 
50 
51 /* FIXME: DIRECT_THREAD_WAIT_INIT is required, but should be optional. */
52 #define DIRECT_THREAD_WAIT_INIT
53 
54 
55 struct __D_DirectThread {
56      int                   magic;
57 
58      pthread_t             thread;      /* The pthread thread identifier. */
59      pid_t                 tid;
60 
61      char                 *name;
62 
63      DirectThreadType      type;        /* The thread's type, e.g. input thread. */
64      DirectThreadMainFunc  main;        /* The thread's main routine (or entry point). */
65      void                 *arg;         /* Custom argument passed to the main routine. */
66 
67      bool                  canceled;    /* Set when direct_thread_cancel() is called. */
68      bool                  joining;     /* Set when direct_thread_join() is called. */
69      bool                  joined;      /* Set when direct_thread_join() has finished. */
70      bool                  detached;    /* Set when direct_thread_detach() is called. */
71      bool                  terminated;  /* Set when direct_thread_terminate() is called. */
72 
73 #ifdef DIRECT_THREAD_WAIT_INIT
74      bool                  init;        /* Set to true before calling the main routine. */
75 #endif
76 
77      pthread_mutex_t       lock;
78      pthread_cond_t        cond;
79 
80      unsigned int          counter;
81 };
82 
83 struct __D_DirectThreadInitHandler {
84      DirectLink            link;
85 
86      int                   magic;
87 
88      DirectThreadInitFunc  func;
89      void                 *arg;
90 };
91 
92 /******************************************************************************/
93 
94 /*
95  * Wrapper around pthread's main routine to pass additional arguments
96  * and setup things like signal masks and scheduling priorities.
97  */
98 static void *direct_thread_main( void *arg );
99 
100 /******************************************************************************/
101 
102 static pthread_mutex_t  handler_lock = PTHREAD_MUTEX_INITIALIZER;
103 static DirectLink      *handlers     = NULL;
104 
105 /******************************************************************************/
106 
107 DirectThreadInitHandler *
direct_thread_add_init_handler(DirectThreadInitFunc func,void * arg)108 direct_thread_add_init_handler( DirectThreadInitFunc  func,
109                                 void                 *arg )
110 {
111      DirectThreadInitHandler *handler;
112 
113      handler = D_CALLOC( 1, sizeof(DirectThreadInitHandler) );
114      if (!handler) {
115           D_WARN( "out of memory" );
116           return NULL;
117      }
118 
119      handler->func = func;
120      handler->arg  = arg;
121 
122      D_MAGIC_SET( handler, DirectThreadInitHandler );
123 
124      pthread_mutex_lock( &handler_lock );
125 
126      direct_list_append( &handlers, &handler->link );
127 
128      pthread_mutex_unlock( &handler_lock );
129 
130      return handler;
131 }
132 
133 void
direct_thread_remove_init_handler(DirectThreadInitHandler * handler)134 direct_thread_remove_init_handler( DirectThreadInitHandler *handler )
135 {
136      D_MAGIC_ASSERT( handler, DirectThreadInitHandler );
137 
138      pthread_mutex_lock( &handler_lock );
139 
140      direct_list_remove( &handlers, &handler->link );
141 
142      pthread_mutex_unlock( &handler_lock );
143 
144      D_MAGIC_CLEAR( handler );
145 
146      D_FREE( handler );
147 }
148 
149 /******************************************************************************/
150 
151 static pthread_mutex_t key_lock   = PTHREAD_MUTEX_INITIALIZER;
152 static pthread_key_t   thread_key = -1;
153 
154 /******************************************************************************/
155 
156 DirectThread *
direct_thread_create(DirectThreadType thread_type,DirectThreadMainFunc thread_main,void * arg,const char * name)157 direct_thread_create( DirectThreadType      thread_type,
158                       DirectThreadMainFunc  thread_main,
159                       void                 *arg,
160                       const char           *name )
161 {
162      DirectThread       *thread;
163      pthread_attr_t      attr;
164      struct sched_param  param;
165      int                 policy;
166      int                 priority;
167      size_t              stack_size;
168 
169      D_ASSERT( thread_main != NULL );
170      D_ASSERT( name != NULL );
171 
172      D_DEBUG_AT( Direct_Thread, "%s( %s, %p(%p), '%s' )\n", __FUNCTION__,
173                  direct_thread_type_name(thread_type), thread_main, arg, name );
174 
175      /* Create the key for the TSD (thread specific data). */
176      pthread_mutex_lock( &key_lock );
177 
178      if (thread_key == -1)
179           pthread_key_create( &thread_key, NULL );
180 
181      pthread_mutex_unlock( &key_lock );
182 
183      /* Allocate thread structure. */
184      thread = D_CALLOC( 1, sizeof(DirectThread) );
185      if (!thread) {
186           D_OOM();
187           return NULL;
188      }
189 
190      /* Write thread information to structure. */
191      thread->name = D_STRDUP( name );
192      thread->type = thread_type;
193      thread->main = thread_main;
194      thread->arg  = arg;
195 
196      /* Initialize to -1 for synchronization. */
197      thread->thread = (pthread_t) -1;
198      thread->tid    = (pid_t) -1;
199 
200      /* Initialize mutex and condition. */
201      direct_util_recursive_pthread_mutex_init( &thread->lock );
202      pthread_cond_init( &thread->cond, NULL );
203 
204      D_MAGIC_SET( thread, DirectThread );
205 
206      /* Initialize scheduling and other parameters. */
207      pthread_attr_init( &attr );
208 
209 #ifdef PTHREAD_EXPLICIT_SCHED
210      pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
211 #endif
212 
213      /* Select scheduler. */
214      switch (direct_config->thread_scheduler) {
215           case DCTS_FIFO:
216                policy = SCHED_FIFO;
217                break;
218 
219           case DCTS_RR:
220                policy = SCHED_RR;
221                break;
222 
223           default:
224                policy = SCHED_OTHER;
225                break;
226      }
227 
228      if (pthread_attr_setschedpolicy( &attr, policy ))
229           D_PERROR( "Direct/Thread: Could not set scheduling policy to %s!\n", direct_thread_policy_name(policy) );
230 
231      /* Read (back) value. */
232      pthread_attr_getschedpolicy( &attr, &policy );
233 
234      /* Select priority. */
235      switch (thread->type) {
236           case DTT_CLEANUP:
237           case DTT_INPUT:
238           case DTT_OUTPUT:
239           case DTT_MESSAGING:
240           case DTT_CRITICAL:
241                priority = thread->type * direct_config->thread_priority_scale / 100;
242                break;
243 
244           default:
245                priority = direct_config->thread_priority;
246                break;
247      }
248 
249      D_DEBUG_AT( Direct_ThreadInit, "  -> %s (%d) [%d;%d]\n", direct_thread_policy_name(policy), priority,
250                  sched_get_priority_min( policy ), sched_get_priority_max( policy ) );
251 
252      if (priority < sched_get_priority_min( policy ))
253           priority = sched_get_priority_min( policy );
254 
255      if (priority > sched_get_priority_max( policy ))
256           priority = sched_get_priority_max( policy );
257 
258      param.sched_priority = priority;
259 
260      if (pthread_attr_setschedparam( &attr, &param ))
261           D_PERROR( "Direct/Thread: Could not set scheduling priority to %d!\n", priority );
262 
263      /* Select stack size? */
264      if (direct_config->thread_stack_size > 0) {
265           if (pthread_attr_setstacksize( &attr, direct_config->thread_stack_size ))
266                D_PERROR( "Direct/Thread: Could not set stack size to %d!\n", direct_config->thread_stack_size );
267      }
268 
269      /* Read (back) value. */
270      pthread_attr_getstacksize( &attr, &stack_size );
271 
272      /* Lock the thread mutex. */
273      D_DEBUG_AT( Direct_ThreadInit, "  -> locking...\n" );
274      pthread_mutex_lock( &thread->lock );
275 
276      /* Create and run the thread. */
277      D_DEBUG_AT( Direct_ThreadInit, "  -> creating...\n" );
278      pthread_create( &thread->thread, &attr, direct_thread_main, thread );
279 
280      pthread_attr_destroy( &attr );
281 
282      pthread_getschedparam( thread->thread, &policy, &param );
283 
284      D_INFO( "Direct/Thread: Started '%s' (%d) [%s %s/%s %d/%d] <%zu>...\n",
285              name, thread->tid, direct_thread_type_name(thread_type),
286              direct_thread_policy_name(policy), direct_thread_scheduler_name(direct_config->thread_scheduler),
287              param.sched_priority, priority, stack_size );
288 
289 #ifdef DIRECT_THREAD_WAIT_INIT
290      /* Wait for completion of the thread's initialization. */
291      while (!thread->init) {
292           D_DEBUG_AT( Direct_ThreadInit, "  -> waiting...\n" );
293           pthread_cond_wait( &thread->cond, &thread->lock );
294      }
295 
296      D_DEBUG_AT( Direct_ThreadInit, "  -> ...thread is running.\n" );
297 #endif
298 
299      /* Unlock the thread mutex. */
300      D_DEBUG_AT( Direct_ThreadInit, "  -> unlocking...\n" );
301      pthread_mutex_unlock( &thread->lock );
302 
303      D_DEBUG_AT( Direct_ThreadInit, "  -> returning %p\n", thread );
304 
305      return thread;
306 }
307 
308 DirectThread *
direct_thread_self(void)309 direct_thread_self( void )
310 {
311      DirectThread *thread = pthread_getspecific( thread_key );
312 
313      if (thread)
314           D_MAGIC_ASSERT( thread, DirectThread );
315 
316      return thread;
317 }
318 
319 const char *
direct_thread_get_name(DirectThread * thread)320 direct_thread_get_name( DirectThread *thread )
321 {
322      D_MAGIC_ASSERT( thread, DirectThread );
323      D_ASSERT( thread->name != NULL );
324 
325      return thread->name;
326 }
327 
328 pid_t
direct_thread_get_tid(DirectThread * thread)329 direct_thread_get_tid( DirectThread *thread )
330 {
331      D_MAGIC_ASSERT( thread, DirectThread );
332 
333      return thread->tid;
334 }
335 
336 __attribute__((no_instrument_function))
337 const char *
direct_thread_self_name(void)338 direct_thread_self_name( void )
339 {
340      DirectThread *thread = pthread_getspecific( thread_key );
341 
342      /*
343       * This function is called by debugging functions, e.g. debug messages, assertions etc.
344       * Therefore no assertions are made here, because they would loop forever if they fail.
345       */
346 
347      return thread ? thread->name : NULL;
348 }
349 
350 void
direct_thread_set_name(const char * name)351 direct_thread_set_name( const char *name )
352 {
353      char         *copy;
354      DirectThread *thread = pthread_getspecific( thread_key );
355 
356      D_DEBUG_AT( Direct_Thread, "%s( '%s' )\n", __FUNCTION__, name );
357 
358      /* Support this function for non-direct threads. */
359      if (!thread) {
360           D_DEBUG_AT( Direct_Thread, "  -> attaching unknown thread %d\n", direct_gettid() );
361 
362           /* Create the key for the TSD (thread specific data). */
363           pthread_mutex_lock( &key_lock );
364 
365           if (thread_key == -1)
366                pthread_key_create( &thread_key, NULL );
367 
368           pthread_mutex_unlock( &key_lock );
369 
370 
371           thread = D_CALLOC( 1, sizeof(DirectThread) );
372           if (!thread) {
373                D_OOM();
374                return;
375           }
376 
377           thread->thread = pthread_self();
378           thread->tid    = direct_gettid();
379 
380           D_MAGIC_SET( thread, DirectThread );
381 
382           pthread_setspecific( thread_key, thread );
383      }
384      else
385           D_DEBUG_AT( Direct_Thread, "  -> was '%s' (%d)\n", thread->name, direct_gettid() );
386 
387      /* Duplicate string. */
388      copy = D_STRDUP( name );
389      if (!copy) {
390           D_OOM();
391           return;
392      }
393 
394      /* Free old string. */
395      if (thread->name)
396           D_FREE( thread->name );
397 
398      /* Keep the copy. */
399      thread->name = copy;
400 }
401 
402 DirectResult
direct_thread_wait(DirectThread * thread,int timeout_ms)403 direct_thread_wait( DirectThread *thread, int timeout_ms )
404 {
405      unsigned int old_counter = thread->counter;
406 
407      D_MAGIC_ASSERT( thread, DirectThread );
408      D_ASSERT( thread->thread != -1 );
409 
410      D_ASSUME( !thread->canceled );
411 
412      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d, %dms )\n", __FUNCTION__,
413                  thread->main, thread->name, thread->tid, timeout_ms );
414 
415      while (old_counter == thread->counter && !thread->terminated)
416           pthread_cond_wait( &thread->cond, &thread->lock );
417 
418      if (thread->terminated)
419           return DR_DEAD;
420 
421      return DR_OK;
422 }
423 
424 void
direct_thread_notify(DirectThread * thread)425 direct_thread_notify( DirectThread *thread )
426 {
427      D_MAGIC_ASSERT( thread, DirectThread );
428      D_ASSERT( thread->thread != -1 );
429 
430      D_ASSUME( !thread->canceled );
431 
432      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
433 
434      pthread_mutex_lock( &thread->lock );
435 
436      thread->counter++;
437 
438      pthread_mutex_unlock( &thread->lock );
439 
440      pthread_cond_broadcast( &thread->cond );
441 }
442 
443 void
direct_thread_lock(DirectThread * thread)444 direct_thread_lock( DirectThread *thread )
445 {
446      D_MAGIC_ASSERT( thread, DirectThread );
447      D_ASSERT( thread->thread != -1 );
448 
449      D_ASSUME( !thread->canceled );
450 
451      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
452 
453      pthread_mutex_lock( &thread->lock );
454 }
455 
456 void
direct_thread_unlock(DirectThread * thread)457 direct_thread_unlock( DirectThread *thread )
458 {
459      D_MAGIC_ASSERT( thread, DirectThread );
460      D_ASSERT( thread->thread != -1 );
461 
462      D_ASSUME( !thread->canceled );
463 
464      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
465 
466      pthread_mutex_unlock( &thread->lock );
467 }
468 
469 void
direct_thread_terminate(DirectThread * thread)470 direct_thread_terminate( DirectThread *thread )
471 {
472      D_MAGIC_ASSERT( thread, DirectThread );
473      D_ASSERT( thread->thread != -1 );
474      D_ASSUME( !pthread_equal( thread->thread, pthread_self() ) );
475 
476      D_ASSUME( !thread->canceled );
477 
478      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
479 
480      thread->terminated = true;
481 
482      direct_thread_notify( thread );
483 }
484 
485 void
direct_thread_cancel(DirectThread * thread)486 direct_thread_cancel( DirectThread *thread )
487 {
488      D_MAGIC_ASSERT( thread, DirectThread );
489      D_ASSERT( thread->thread != -1 );
490      D_ASSERT( !pthread_equal( thread->thread, pthread_self() ) );
491 
492      D_ASSUME( !thread->canceled );
493 
494      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
495 
496      thread->canceled = true;
497 
498 #if DIRECT_BUILD_NO_PTHREAD_CANCEL
499      D_UNIMPLEMENTED();
500 #else
501      pthread_cancel( thread->thread );
502 #endif
503 }
504 
505 bool
direct_thread_is_canceled(DirectThread * thread)506 direct_thread_is_canceled( DirectThread *thread )
507 {
508      D_MAGIC_ASSERT( thread, DirectThread );
509 
510      return thread->canceled;
511 }
512 
513 void
direct_thread_detach(DirectThread * thread)514 direct_thread_detach( DirectThread *thread )
515 {
516      D_MAGIC_ASSERT( thread, DirectThread );
517      D_ASSERT( thread->thread != -1 );
518      D_ASSERT( !pthread_equal( thread->thread, pthread_self() ) );
519 
520      D_ASSUME( !thread->canceled );
521 
522      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
523 
524      thread->detached = true;
525 
526      pthread_detach( thread->thread );
527 }
528 
529 bool
direct_thread_is_detached(DirectThread * thread)530 direct_thread_is_detached( DirectThread *thread )
531 {
532      D_MAGIC_ASSERT( thread, DirectThread );
533 
534      return thread->detached;
535 }
536 
537 void
direct_thread_testcancel(DirectThread * thread)538 direct_thread_testcancel( DirectThread *thread )
539 {
540      D_MAGIC_ASSERT( thread, DirectThread );
541      D_ASSERT( thread->thread != -1 );
542      D_ASSERT( pthread_equal( thread->thread, pthread_self() ) );
543 
544 #if DIRECT_BUILD_NO_PTHREAD_CANCEL
545      D_UNIMPLEMENTED();
546 #else
547      /* Quick check before calling the pthread function. */
548      if (thread->canceled)
549           pthread_testcancel();
550 #endif
551 }
552 
553 void
direct_thread_join(DirectThread * thread)554 direct_thread_join( DirectThread *thread )
555 {
556      D_MAGIC_ASSERT( thread, DirectThread );
557      D_ASSERT( thread->thread != -1 );
558 
559      D_ASSUME( !pthread_equal( thread->thread, pthread_self() ) );
560      D_ASSUME( !thread->joining );
561      D_ASSUME( !thread->joined );
562      D_ASSUME( !thread->detached );
563 
564      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
565 
566      if (thread->detached) {
567           D_DEBUG_AT( Direct_Thread, "  -> DETACHED!\n" );
568           return;
569      }
570 
571      if (!thread->joining && !pthread_equal( thread->thread, pthread_self() )) {
572           thread->joining = true;
573 
574           D_DEBUG_AT( Direct_Thread, "  -> joining...\n" );
575 
576           pthread_join( thread->thread, NULL );
577 
578           thread->joined = true;
579 
580           D_DEBUG_AT( Direct_Thread, "  -> joined.\n" );
581      }
582 }
583 
584 bool
direct_thread_is_joined(DirectThread * thread)585 direct_thread_is_joined( DirectThread *thread )
586 {
587      D_MAGIC_ASSERT( thread, DirectThread );
588 
589      return thread->joined;
590 }
591 
592 void
direct_thread_destroy(DirectThread * thread)593 direct_thread_destroy( DirectThread *thread )
594 {
595      D_MAGIC_ASSERT( thread, DirectThread );
596      D_ASSUME( !pthread_equal( thread->thread, pthread_self() ) );
597      D_ASSUME( !thread->detached );
598 
599      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
600 
601      if (thread->detached) {
602           D_DEBUG_AT( Direct_Thread, "  -> DETACHED!\n" );
603           return;
604      }
605 
606      if (!thread->joined && !pthread_equal( thread->thread, pthread_self() )) {
607           if (thread->canceled)
608                D_DEBUG_AT( Direct_Thread, "  -> cancled but not joined!\n" );
609           else {
610                D_DEBUG_AT( Direct_Thread, "  -> still running!\n" );
611 
612                if (thread->name)
613                     D_ERROR( "Direct/Thread: Canceling '%s' (%d)!\n", thread->name, thread->tid );
614                else
615                     D_ERROR( "Direct/Thread: Canceling %d!\n", thread->tid );
616 
617                thread->detached = true;
618 
619                pthread_detach( thread->thread );
620 
621                direct_thread_cancel( thread );
622 
623                return;
624           }
625      }
626 
627      D_MAGIC_CLEAR( thread );
628 
629      D_FREE( thread->name );
630      D_FREE( thread );
631 }
632 
633 /******************************************************************************/
634 
635 #if DIRECT_BUILD_TEXT
636 const char *
direct_thread_type_name(DirectThreadType type)637 direct_thread_type_name( DirectThreadType type )
638 {
639      switch (type) {
640           case DTT_DEFAULT:
641                return "DEFAULT";
642 
643           case DTT_CLEANUP:
644                return "CLEANUP";
645 
646           case DTT_INPUT:
647                return "INPUT";
648 
649           case DTT_OUTPUT:
650                return "OUTPUT";
651 
652           case DTT_MESSAGING:
653                return "MESSAGING";
654 
655           case DTT_CRITICAL:
656                return "CRITICAL";
657      }
658 
659      return "<unknown>";
660 }
661 
662 const char *
direct_thread_scheduler_name(DirectConfigThreadScheduler scheduler)663 direct_thread_scheduler_name( DirectConfigThreadScheduler scheduler )
664 {
665      switch (scheduler) {
666           case DCTS_OTHER:
667                return "OTHER";
668 
669           case DCTS_FIFO:
670                return "FIFO";
671 
672           case DCTS_RR:
673                return "RR";
674      }
675 
676      return "<unknown>";
677 }
678 
679 const char *
direct_thread_policy_name(int policy)680 direct_thread_policy_name( int policy )
681 {
682      switch (policy) {
683           case SCHED_OTHER:
684                return "OTHER";
685 
686           case SCHED_FIFO:
687                return "FIFO";
688 
689           case SCHED_RR:
690                return "RR";
691      }
692 
693      return "<unknown>";
694 }
695 #endif
696 
697 /******************************************************************************/
698 
699 static void
direct_thread_cleanup(void * arg)700 direct_thread_cleanup( void *arg )
701 {
702      DirectThread *thread = arg;
703 
704      D_MAGIC_ASSERT( thread, DirectThread );
705 
706      D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid );
707 
708      if (thread->detached) {
709           D_MAGIC_CLEAR( thread );
710 
711           D_FREE( thread->name );
712           D_FREE( thread );
713      }
714 }
715 
716 /******************************************************************************/
717 
718 static void *
direct_thread_main(void * arg)719 direct_thread_main( void *arg )
720 {
721      void                    *ret;
722      DirectThread            *thread = arg;
723      DirectThreadInitHandler *handler;
724      pid_t                    tid;
725 
726      tid = direct_gettid();
727 
728      D_DEBUG_AT( Direct_ThreadInit, "%s( %p ) <- tid %d\n", __FUNCTION__, arg, tid );
729 
730      D_DEBUG_AT( Direct_ThreadInit, "  -> starting...\n" );
731 
732      D_MAGIC_ASSERT( thread, DirectThread );
733 
734      pthread_cleanup_push( direct_thread_cleanup, thread );
735 
736 
737      pthread_setspecific( thread_key, thread );
738 
739      thread->tid = tid;
740 
741 
742      /* Call all init handlers. */
743      pthread_mutex_lock( &handler_lock );
744 
745      direct_list_foreach (handler, handlers)
746           handler->func( thread, handler->arg );
747 
748      pthread_mutex_unlock( &handler_lock );
749 
750 
751      /* Have all signals handled by the main thread. */
752      if (direct_config->thread_block_signals)
753           direct_signals_block_all();
754 
755      /* Lock the thread mutex. */
756      D_DEBUG_AT( Direct_ThreadInit, "  -> locking...\n" );
757      pthread_mutex_lock( &thread->lock );
758 
759      /* Indicate that our initialization has completed. */
760      thread->init = true;
761 
762 #ifdef DIRECT_THREAD_WAIT_INIT
763      D_DEBUG_AT( Direct_ThreadInit, "  -> signalling...\n" );
764      pthread_cond_signal( &thread->cond );
765 #endif
766 
767      /* Unlock the thread mutex. */
768      D_DEBUG_AT( Direct_ThreadInit, "  -> unlocking...\n" );
769      pthread_mutex_unlock( &thread->lock );
770 
771      if (thread->joining) {
772           D_DEBUG_AT( Direct_Thread, "  -> Being joined before entering main routine!\n" );
773           return NULL;
774      }
775 
776      D_MAGIC_ASSERT( thread, DirectThread );
777 
778      /* Call main routine. */
779      D_DEBUG_AT( Direct_ThreadInit, "  -> running...\n" );
780      ret = thread->main( thread, thread->arg );
781 
782      D_DEBUG_AT( Direct_Thread, "  -> Returning %p from '%s' (%s, %d)...\n",
783                  ret, thread->name, direct_thread_type_name(thread->type), thread->tid );
784 
785      D_MAGIC_ASSERT( thread, DirectThread );
786 
787      pthread_cleanup_pop( 1 );
788 
789      return ret;
790 }
791 
792