]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/compat/posix/v2_0/src/pthread.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / compat / posix / v2_0 / src / pthread.cxx
1 //==========================================================================
2 //
3 //      pthread.cxx
4 //
5 //      POSIX pthreads implementation
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):           nickg
44 // Contributors:        nickg, jlarmour
45 // Date:                2000-03-27
46 // Purpose:             POSIX pthread implementation
47 // Description:         This file contains the implementation of the POSIX pthread
48 //                      functions.
49 //              
50 //              
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <pkgconf/hal.h>
57 #include <pkgconf/kernel.h>
58 #include <pkgconf/posix.h>
59 #include <pkgconf/isoinfra.h>
60 #include <pkgconf/libc_startup.h>
61
62 #include <cyg/kernel/ktypes.h>         // base kernel types
63 #include <cyg/infra/cyg_trac.h>        // tracing macros
64 #include <cyg/infra/cyg_ass.h>         // assertion macros
65
66 #include "pprivate.h"                   // POSIX private header
67
68 #include <stdlib.h>                     // malloc(), free()
69
70 #include <cyg/kernel/sched.hxx>        // scheduler definitions
71 #include <cyg/kernel/thread.hxx>       // thread definitions
72 #include <cyg/kernel/clock.hxx>        // clock definitions
73
74 #include <cyg/kernel/sched.inl>        // scheduler inlines
75
76 //-----------------------------------------------------------------------------
77 // First check that the configuration contains the elements we need
78
79 #ifndef CYGPKG_KERNEL
80 #error POSIX pthread need eCos kernel
81 #endif
82
83 #ifndef CYGSEM_KERNEL_SCHED_MLQUEUE
84 #error POSIX pthreads need MLQ scheduler
85 #endif
86
87 #ifndef CYGSEM_KERNEL_SCHED_TIMESLICE
88 #error POSIX pthreads need timeslicing
89 #endif
90
91 #ifndef CYGVAR_KERNEL_THREADS_DATA
92 #error POSIX pthreads need per-thread data
93 #endif
94
95 //=============================================================================
96 // Internal data structures
97
98 // Mutex for controlling access to shared data structures
99 Cyg_Mutex pthread_mutex CYGBLD_POSIX_INIT;
100
101 // Array of pthread control structures. A pthread_t object is
102 // "just" an index into this array.
103 static pthread_info *thread_table[CYGNUM_POSIX_PTHREAD_THREADS_MAX];
104
105 // Count of number of threads in table.
106 static int pthread_count = 0;
107
108 // Count of number of threads that have exited and not been reaped.
109 static int pthreads_exited;
110
111 // Count of number of threads that are waiting to be joined
112 static int pthreads_tobejoined;
113
114 // Per-thread key allocation. This key map has a 1 bit set for each
115 // key that is free, zero if it is allocated.
116 #define KEY_MAP_TYPE cyg_uint32
117 #define KEY_MAP_TYPE_SIZE (sizeof(KEY_MAP_TYPE)*8) // in BITS!
118 static KEY_MAP_TYPE thread_key[PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE];
119 static void (*key_destructor[PTHREAD_KEYS_MAX]) (void *);
120     
121 // Index of next pthread_info to allocate from thread_table array.
122 static int thread_info_next = 0;
123
124 // This is used to make pthread_t values unique even when reusing
125 // a table slot. This allows CYGNUM_POSIX_PTHREAD_THREADS_MAX to range
126 // up to 1024.
127 #define THREAD_ID_COOKIE_INC 0x00000400
128 #define THREAD_ID_COOKIE_MASK (THREAD_ID_COOKIE_INC-1)
129 static pthread_t thread_id_cookie = THREAD_ID_COOKIE_INC;
130
131 //-----------------------------------------------------------------------------
132 // Main thread.
133
134 #define MAIN_DEFAULT_STACK_SIZE \
135   (CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE < PTHREAD_STACK_MIN \
136               ? PTHREAD_STACK_MIN : CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE)
137
138 static char main_stack[MAIN_DEFAULT_STACK_SIZE];
139
140 // Thread ID of main thread.
141 static pthread_t main_thread;
142
143 //=============================================================================
144 // Exported variables
145
146 int pthread_canceled_dummy_var;           // pointed to by PTHREAD_CANCELED
147
148 //=============================================================================
149 // Internal functions
150
151 //-----------------------------------------------------------------------------
152 // Private version of pthread_self() that returns a pointer to our internal
153 // control structure.
154
155 pthread_info *pthread_self_info(void)
156 {
157     Cyg_Thread *thread = Cyg_Thread::self();
158
159     CYG_CHECK_DATA_PTR(thread, "Illegal current thread");
160     
161     pthread_info *info = (pthread_info *)thread->get_data(CYGNUM_KERNEL_THREADS_DATA_POSIX);
162
163     // This assertion mustn't be enabled because sometimes we can legitimately
164     // carefully call this as long as we realise the value can be NULL.
165     // e.g. consider the use of this when inheriting sigmasks when in the
166     // context of creating the main() thread.
167 //    CYG_CHECK_DATA_PTR(info, "Not a POSIX thread!!!");
168
169     return info;
170 }
171
172 externC pthread_info *pthread_info_id( pthread_t id )
173 {
174     pthread_t index = id & THREAD_ID_COOKIE_MASK;
175
176     pthread_info *info = thread_table[index];
177
178     // Check for a valid entry
179     if( info == NULL )
180         return NULL;
181     
182     // Check that this is a valid entry
183     if ( info->state == PTHREAD_STATE_FREE ||
184          info->state == PTHREAD_STATE_EXITED )
185         return NULL;
186
187     // Check that the entry matches the id
188     if( info->id != id ) return NULL;
189
190     // Return the pointer
191     return info;
192 }
193
194 //-----------------------------------------------------------------------------
195 // new operator to allow us to invoke the Cyg_Thread constructor on the
196 // pthread_info.thread_obj array.
197
198 inline void *operator new(size_t size,  cyg_uint8 *ptr) { return (void *)ptr; };
199
200 //-----------------------------------------------------------------------------
201 // Optional memory allocation functions for pthread stacks.
202 // If there is an implementation of malloc() available, define pthread_malloc()
203 // and pthread_free() to use it. Otherwise define them to do nothing.
204 // In the future we may want to add configuration here to permit thread stacks
205 // to be allocated in a nominated memory pool separate from the standard malloc()
206 // pool. Hence the (currently redundant) encapsulation of these functions.
207
208 #if CYGINT_ISO_MALLOC
209
210 static __inline__ CYG_ADDRWORD pthread_malloc( CYG_ADDRWORD size )
211 {
212     return (CYG_ADDRWORD)malloc( size );
213 }
214
215 static __inline__ void pthread_free( CYG_ADDRWORD m )
216 {
217     free( (void *)m );
218 }
219
220 #define PTHREAD_MALLOC
221
222 #else
223
224 #define pthread_malloc(_x_) (0)
225
226 #define pthread_free(_x_)
227
228 #endif
229
230 //-----------------------------------------------------------------------------
231 // pthread entry function.
232 // does some housekeeping and then calls the user's start routine.
233
234 static void pthread_entry(CYG_ADDRWORD data)
235 {
236     pthread_info *self = (pthread_info *)data;
237
238     void *retval = self->start_routine(self->start_arg);
239
240     pthread_exit( retval );
241 }
242
243 //-----------------------------------------------------------------------------
244 // Main entry function.
245 // This is set as the start_routine of the main thread. It invokes main()
246 // and if it returns, shuts down the system.
247
248 externC void cyg_libc_invoke_main( void );
249
250 static void *call_main( void * )
251 {
252     cyg_libc_invoke_main();
253     return NULL; // placate compiler
254 }
255
256 //-----------------------------------------------------------------------------
257 // Check whether there is a cancel pending and if so, whether
258 // cancellations are enabled. We do it in this order to reduce the
259 // number of tests in the common case - when no cancellations are
260 // pending.
261 // We make this inline so it can be called directly below for speed
262
263 static __inline__ int
264 checkforcancel( void )
265 {
266      pthread_info *self = pthread_self_info();
267
268     if( self != NULL &&
269         self->cancelpending &&
270         self->cancelstate == PTHREAD_CANCEL_ENABLE )
271         return 1;
272     else
273         return 0;
274 }
275
276
277 //-----------------------------------------------------------------------------
278 // POSIX ASR
279 // This is installed as the ASR for all POSIX threads.
280
281 static void posix_asr( CYG_ADDRWORD data )
282 {
283     pthread_info *self = (pthread_info *)data;
284
285 #ifdef CYGPKG_POSIX_TIMERS
286     // Call into timer subsystem to deliver any pending
287     // timer expirations.
288     cyg_posix_timer_asr(self);
289 #endif
290     
291 #ifdef CYGPKG_POSIX_SIGNALS
292     // Call signal subsystem to deliver any signals
293     cyg_posix_signal_asr(self);
294 #endif
295     
296     // Check for cancellation
297     if( self->cancelpending &&
298         self->cancelstate == PTHREAD_CANCEL_ENABLE &&
299         self->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS )
300     {
301         // If we have a pending cancellation, cancellations are
302         // enabled and we are in asynchronous mode, then we can do the
303         // cancellation processing.  Since pthread_exit() does
304         // everything we need to do, we just call that here.
305         
306         pthread_exit(PTHREAD_CANCELED);
307     }
308 }
309
310 //-----------------------------------------------------------------------------
311 // The (Grim) Reaper.
312 // This function is called to tidy up and dispose of any threads that have
313 // exited. This work must be done from a thread other than the one exiting.
314 // Note: this function _must_ be called with pthread_mutex locked.
315
316 static void pthread_reap()
317 {
318     int i;
319
320     // Loop over the thread table looking for exited threads. The
321     // pthreads_exited counter springs us out of this once we have
322     // found them all (and keeps us out if there are none to do).
323    
324     for( i = 0; pthreads_exited && i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
325     {
326         pthread_info *thread = thread_table[i];
327
328         if( thread != NULL && thread->state == PTHREAD_STATE_EXITED )
329         {
330             // The thread has exited, so it is a candidate for being
331             // reaped. We have to make sure that the eCos thread has
332             // also reached EXITED state before we can tidy it up.
333
334             while( thread->thread->get_state() != Cyg_Thread::EXITED )
335             {
336                 // The eCos thread has not yet exited. This is
337                 // probably because its priority is too low to allow
338                 // it to complete.  We fix this here by raising its
339                 // priority to equal ours and then yielding. This
340                 // should eventually get it into exited state.
341
342                 Cyg_Thread *self = Cyg_Thread::self();
343
344                 // Set thread's priority to our current dispatching priority.
345                 thread->thread->set_priority( self->get_current_priority() );
346
347                 // Yield, yield
348                 self->yield();
349     
350                 // and keep looping until he exits.
351             }
352
353             // At this point we have a thread that we can reap.
354
355             // destroy the eCos thread
356             thread->thread->~Cyg_Thread();
357
358             // destroy the joiner condvar
359             thread->joiner->~Cyg_Condition_Variable();
360
361 #ifdef CYGPKG_POSIX_SIGNALS
362             // Destroy signal handling fields
363             cyg_posix_thread_sigdestroy( thread );
364 #endif
365             
366             // Free the stack if we allocated it
367             if( thread->freestack )
368                 pthread_free( thread->stackmem );
369
370             // Finally, set the thread table entry to NULL so that it
371             // may be reused.
372             thread_table[i] = NULL;
373
374             pthread_count--;
375             pthreads_exited--;
376         }
377     }
378 }
379
380 //=============================================================================
381 // Functions exported to rest of POSIX subsystem.
382
383 //-----------------------------------------------------------------------------
384 // Create the main() thread.
385
386 externC void cyg_posix_pthread_start( void )
387 {
388
389     // Initialize the per-thread data key map.
390
391     for( cyg_ucount32 i = 0; i < (PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE); i++ )
392     {
393         thread_key[i] = ~0;
394     }
395     
396     // Create the main thread
397     pthread_attr_t attr;
398     struct sched_param schedparam;
399
400     schedparam.sched_priority = CYGNUM_POSIX_MAIN_DEFAULT_PRIORITY;
401
402     pthread_attr_init( &attr );
403     pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
404     pthread_attr_setstackaddr( &attr, &main_stack[sizeof(main_stack)] );
405     pthread_attr_setstacksize( &attr, sizeof(main_stack) );
406     pthread_attr_setschedpolicy( &attr, SCHED_RR );
407     pthread_attr_setschedparam( &attr, &schedparam );
408     
409     pthread_create( &main_thread, &attr, call_main, NULL );    
410 }
411
412 #ifdef CYGPKG_POSIX_SIGNALS
413 //-----------------------------------------------------------------------------
414 // Look for a thread that can accept delivery of any of the signals in
415 // the mask and release it from any wait it is in.  Since this may be
416 // called from a DSR, it cannot use any locks internally - any locking
417 // should be done before the call.
418
419 externC void cyg_posix_pthread_release_thread( sigset_t *mask )
420 {
421     int i;
422     int count = pthread_count;
423     
424     // Loop over the thread table looking for a thread that has a
425     // signal mask that does not mask all the signals in mask.
426     // FIXME: find a more efficient way of doing this.
427     
428     for( i = 0; count > 0 && i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
429     {
430         pthread_info *thread = thread_table[i];
431
432         if( (thread != NULL) &&
433             (thread->state <= PTHREAD_STATE_RUNNING) &&
434             ((*mask & ~thread->sigmask) != 0) )
435         {
436             // This thread can service at least one of the signals in
437             // *mask. Knock it out of its wait and make its ASR pending.
438
439             thread->thread->set_asr_pending();
440             thread->thread->release();
441             break;
442         }
443
444         // Decrement count for each valid thread we find.
445         if( thread != NULL && thread->state != PTHREAD_STATE_FREE )
446             count--;
447     }
448 }
449 #endif
450
451 //=============================================================================
452 // General thread operations
453
454 //-----------------------------------------------------------------------------
455 // Thread creation and management.
456
457 // Create a thread.
458 externC int pthread_create ( pthread_t *thread,
459                              const pthread_attr_t *attr,
460                              void *(*start_routine) (void *),
461                              void *arg)
462 {
463     PTHREAD_ENTRY();
464
465     PTHREAD_CHECK(thread);
466     PTHREAD_CHECK(start_routine);
467
468     pthread_info *self = pthread_self_info();
469     
470     pthread_attr_t use_attr;
471
472     // Set use_attr to the set of attributes we are going to
473     // actually use. Either those passed in, or the default set.
474    
475     if( attr == NULL )
476         pthread_attr_init( &use_attr );
477     else use_attr = *attr;
478
479     // Adjust the attributes to cope with the setting of inheritsched.
480
481     if( use_attr.inheritsched == PTHREAD_INHERIT_SCHED )
482     {
483         CYG_ASSERT( NULL != self,
484                     "Attempt to inherit sched policy from non-POSIX thread" );
485 #ifdef CYGDBG_USE_ASSERTS
486         // paranoia check
487         int i;
488         for (i=(sizeof(thread_table)/sizeof(*thread_table))-1; i>=0; i--) {
489             if (thread_table[i] == self)
490                 break;
491         }
492         CYG_ASSERT( i>=0, "Current pthread not found in table" );
493 #endif
494         use_attr.schedpolicy = self->attr.schedpolicy;
495         use_attr.schedparam  = self->attr.schedparam;
496     }
497
498     CYG_ADDRWORD stackbase, stacksize;
499     cyg_bool freestack = false;
500     CYG_ADDRWORD stackmem = 0;
501     
502     // If the stack size is not valid, we can assume that it is at
503     // least PTHREAD_STACK_MIN bytes.
504         
505     if( use_attr.stacksize_valid )
506         stacksize = use_attr.stacksize;
507     else stacksize = PTHREAD_STACK_MIN;
508
509     if( use_attr.stackaddr_valid )
510     {
511         // Set up stack base and size from supplied arguments.
512
513         // Calculate stack base from address and size.
514         // FIXME: Falling stack assumed in pthread_create().
515         stackmem = stackbase = (CYG_ADDRWORD)use_attr.stackaddr-stacksize;
516     }
517     else
518     {
519 #ifdef PTHREAD_MALLOC
520
521         stackmem = stackbase = pthread_malloc( stacksize );
522
523         if( stackmem == 0 )
524             PTHREAD_RETURN( EAGAIN );
525
526         freestack = true;
527 #else        
528         PTHREAD_RETURN(EINVAL);
529 #endif        
530         
531     }
532
533     // Get sole access to data structures
534     
535     pthread_mutex.lock();
536     
537     // Dispose of any dead threads
538     pthread_reap();
539     
540     // Find a free slot in the thread table
541     
542     pthread_info *nthread;
543     int thread_next = thread_info_next;
544     
545     while( thread_table[thread_next] != NULL )
546     {
547         thread_next++;
548         if( thread_next >= CYGNUM_POSIX_PTHREAD_THREADS_MAX )
549             thread_next = 0;
550
551         // check for wrap, and return error if no slots left
552         if( thread_next == thread_info_next )
553         {
554             pthread_mutex.unlock();
555             if( freestack )
556                 pthread_free( stackmem );
557             PTHREAD_RETURN(ENOMEM);
558         }
559     }
560
561     nthread = (pthread_info *)stackbase;
562
563     stackbase += sizeof(pthread_info);
564     stacksize -= sizeof(pthread_info);
565     
566     thread_table[thread_next] = nthread;
567
568     // Set new next index
569     thread_info_next = thread_next;
570     
571     // step the cookie
572     thread_id_cookie += THREAD_ID_COOKIE_INC;
573
574     // Initialize the table entry
575     nthread->state              = use_attr.detachstate == PTHREAD_CREATE_JOINABLE ?
576                                   PTHREAD_STATE_RUNNING : PTHREAD_STATE_DETACHED;
577     nthread->id                 = thread_next+thread_id_cookie;
578     nthread->attr               = use_attr;
579     nthread->retval             = 0;
580     nthread->start_routine      = start_routine;
581     nthread->start_arg          = arg;
582
583     nthread->freestack          = freestack;
584     nthread->stackmem           = stackmem;
585     
586     nthread->cancelstate        = PTHREAD_CANCEL_ENABLE;
587     nthread->canceltype         = PTHREAD_CANCEL_DEFERRED;
588     nthread->cancelbuffer       = NULL;
589     nthread->cancelpending      = false;
590
591     nthread->thread_data        = NULL;
592     
593 #ifdef CYGVAR_KERNEL_THREADS_NAME    
594     // generate a name for this thread
595
596     char *name = nthread->name;
597     static char *name_template = "pthread.00000000";
598     pthread_t id = nthread->id;
599     
600     for( int i = 0; name_template[i]; i++ ) name[i] = name_template[i];
601
602     // dump the id, in hex into the name.
603     for( int i = 15; i >= 8; i-- )
604     {
605         name[i] = "0123456789ABCDEF"[id&0xF];
606         id >>= 4;
607     }
608
609 #endif
610
611     // Initialize the joiner condition variable
612
613     nthread->joiner = new(nthread->joiner_obj) Cyg_Condition_Variable( pthread_mutex );
614
615 #ifdef CYGPKG_POSIX_SIGNALS
616     // Initialize signal specific fields.
617     if (NULL != self) {
618         CYG_CHECK_DATA_PTR( self,
619                             "Attempt to inherit signal mask from bogus pthread" );
620 #ifdef CYGDBG_USE_ASSERTS
621         // paranoia check
622         int i;
623         for (i=(sizeof(thread_table)/sizeof(*thread_table))-1; i>=0; i--) {
624             if (thread_table[i] == self)
625                 break;
626         }
627         CYG_ASSERT( i>=0, "Current pthread not found in table" );
628 #endif
629     }
630     cyg_posix_thread_siginit( nthread, self );
631 #endif
632
633     // create the underlying eCos thread
634
635     nthread->thread = new(&nthread->thread_obj[0])
636         Cyg_Thread ( PTHREAD_ECOS_PRIORITY(use_attr.schedparam.sched_priority),
637                      pthread_entry,
638                      (CYG_ADDRWORD)nthread,
639 #ifdef CYGVAR_KERNEL_THREADS_NAME
640                      name,
641 #else
642                      NULL,
643 #endif
644                      stackbase,
645                      stacksize);
646
647     // Put pointer to pthread_info into eCos thread's per-thread data.
648     nthread->thread->set_data( CYGNUM_KERNEL_THREADS_DATA_POSIX, (CYG_ADDRWORD)nthread );
649
650     // Set timeslice enable according to scheduling policy.
651     if( use_attr.schedpolicy == SCHED_FIFO )
652          nthread->thread->timeslice_disable();
653     else nthread->thread->timeslice_enable();
654
655     // set up ASR and data
656     nthread->thread->set_asr( posix_asr, (CYG_ADDRWORD)nthread, NULL, NULL );    
657     
658     // return thread ID
659     *thread = nthread->id;
660
661     pthread_count++;
662                 
663     pthread_mutex.unlock();
664
665     // finally, set the thread going
666     nthread->thread->resume();
667     
668     PTHREAD_RETURN(0);
669 }
670
671 //-----------------------------------------------------------------------------
672 // Get current thread id.
673
674 externC pthread_t pthread_self ( void )
675 {
676     PTHREAD_ENTRY();
677     
678     pthread_info *info = pthread_self_info();
679
680     CYG_CHECK_DATA_PTR(info, "Not a POSIX thread!!!");
681     
682     return info->id;
683 }
684
685 //-----------------------------------------------------------------------------
686 // Compare two thread identifiers.
687
688 externC int pthread_equal (pthread_t thread1, pthread_t thread2)
689 {
690     PTHREAD_ENTRY();
691     
692     return thread1 == thread2;
693 }
694
695 //-----------------------------------------------------------------------------
696 // Terminate current thread.
697
698 externC void exit(int) CYGBLD_ATTRIB_NORET;
699
700 externC void pthread_exit (void *retval)
701 {
702     PTHREAD_ENTRY();
703     
704     pthread_info *self = pthread_self_info();
705
706     // Disable cancellation requests for this thread.  If cleanup
707     // handlers exist, they will generally be issuing system calls
708     // to clean up resources.  We want these system calls to run
709     // without cancelling, and we also want to prevent being
710     // re-cancelled.
711     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
712
713     // Call cancellation handlers. We eat up the buffers as we go in
714     // case any of the routines calls pthread_exit() itself.
715     while( self->cancelbuffer != NULL )
716     {
717         struct pthread_cleanup_buffer *buffer = self->cancelbuffer;
718
719         self->cancelbuffer = buffer->prev;
720
721         buffer->routine(buffer->arg);
722     }
723
724     if( self->thread_data != NULL )
725     {
726         // Call per-thread key destructors.
727         // The specification of this is that we must continue to call the
728         // destructor functions until all the per-thread data values are NULL or
729         // we have done it PTHREAD_DESTRUCTOR_ITERATIONS times.
730     
731         cyg_bool destructors_called;
732         int destructor_iterations = 0;
733
734         do
735         {
736             destructors_called = false;
737         
738             for( cyg_ucount32 key = 0; key < PTHREAD_KEYS_MAX; key++ )
739             {
740                 // Skip unallocated keys
741                 if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
742                     continue;
743
744                 // Skip NULL destructors
745                 if( key_destructor[key] == NULL ) continue;
746
747                 // Skip NULL data values
748                 if( self->thread_data[key] == NULL ) continue;
749
750                 // If it passes all that, call the destructor.
751                 // Note that NULLing the data value here is new
752                 // behaviour in the 2001 POSIX standard.
753                 {
754                     void* value = self->thread_data[key];
755                     self->thread_data[key] = NULL;
756                     key_destructor[key](value);
757                 }
758
759                 // Record that we called a destructor
760                 destructors_called = true;
761             }
762
763             // Count the iteration
764             destructor_iterations++;
765         
766         } while( destructors_called &&
767                  (destructor_iterations <= PTHREAD_DESTRUCTOR_ITERATIONS));
768
769     }
770     
771     pthread_mutex.lock();
772
773     // Set the retval for any joiner
774     self->retval = retval;
775
776     // If we are already detached, go to EXITED state, otherwise
777     // go into JOIN state.
778     
779     if ( PTHREAD_STATE_DETACHED == self->state ) {
780         self->state = PTHREAD_STATE_EXITED;
781         pthreads_exited++;
782     } else {
783         self->state = PTHREAD_STATE_JOIN;
784         pthreads_tobejoined++;
785     }
786
787     // Kick any waiting joiners
788     self->joiner->broadcast();
789
790     cyg_bool call_exit=false;
791
792     // if this is the last thread (other than threads waiting to be joined)
793     // then we need to call exit() later
794     if ( pthreads_exited + pthreads_tobejoined == pthread_count )
795         call_exit=true;
796
797     pthread_mutex.unlock();
798     
799     // Finally, call the exit function; this will not return.
800     if ( call_exit )
801         ::exit(0);
802     else
803         self->thread->exit();
804
805     // This loop keeps some compilers happy. pthread_exit() is marked
806     // with the noreturn attribute, and without this they generate a
807     // call to abort() here in case Cyg_Thread::exit() returns. 
808     
809     for(;;) continue;
810 }
811
812 //-----------------------------------------------------------------------------
813 // Wait for the thread to terminate. If thread_return is not NULL then
814 // the retval from the thread's call to pthread_exit() is stored at
815 // *thread_return.
816
817 externC int pthread_join (pthread_t thread, void **thread_return)
818 {
819     int err = 0;
820
821     PTHREAD_ENTRY();
822     
823     // check for cancellation first.
824     pthread_testcancel();
825
826     pthread_mutex.lock();
827     
828     // Dispose of any dead threads
829     pthread_reap();
830     
831     pthread_info *self = pthread_self_info();
832     pthread_info *joinee = pthread_info_id( thread );
833
834     if( joinee == NULL )
835     {
836         err = ESRCH;
837     }
838
839     if( !err && joinee == self )
840     {
841         err = EDEADLK;
842     }
843
844     if ( !err ) {
845         switch ( joinee->state )
846         {
847         case PTHREAD_STATE_RUNNING:
848             // The thread is still running, we must wait for it.
849         while( joinee->state == PTHREAD_STATE_RUNNING ) {
850             if ( !joinee->joiner->wait() )
851                 // check if we were woken because we were being cancelled
852                 if ( checkforcancel() ) {
853                     err = EAGAIN;  // value unimportant, just some error
854                     break;
855                 }
856         }
857
858         // check that the thread is still joinable
859         if( joinee->state == PTHREAD_STATE_JOIN )
860             break;
861
862         // The thread has become unjoinable while we waited, so we
863         // fall through to complain.
864         
865         case PTHREAD_STATE_FREE:
866         case PTHREAD_STATE_DETACHED:
867         case PTHREAD_STATE_EXITED:
868         // None of these may be joined.
869             err = EINVAL;
870             break;
871             
872         case PTHREAD_STATE_JOIN:
873             break;
874         }
875     }
876
877     if ( !err ) {
878     
879         // here, we know that joinee is a thread that has exited and is
880         // ready to be joined.
881
882         // Get the retval
883         if( thread_return != NULL )
884             *thread_return = joinee->retval;
885         
886         // set state to exited.
887         joinee->state = PTHREAD_STATE_EXITED;
888         pthreads_exited++;
889         pthreads_tobejoined--;
890     
891         // Dispose of any dead threads
892         pthread_reap();
893     }
894
895     pthread_mutex.unlock();
896     
897     // check for cancellation before returning
898     pthread_testcancel();
899
900     PTHREAD_RETURN(err);
901 }
902
903 //-----------------------------------------------------------------------------
904 // Set the detachstate of the thread to "detached". The thread then does not
905 // need to be joined and its resources will be freed when it exits.
906
907 externC int pthread_detach (pthread_t thread)
908 {
909     PTHREAD_ENTRY();
910     
911     int ret = 0;
912     
913     pthread_mutex.lock();
914
915     pthread_info *detachee = pthread_info_id( thread );
916     
917     if( detachee == NULL )
918         ret = ESRCH;                    // No such thread
919     else if( detachee->state == PTHREAD_STATE_DETACHED )
920         ret = EINVAL;                   // Already detached!
921     else
922     {
923         // Set state to detached and kick any joinees to
924         // make them return.
925         detachee->state = PTHREAD_STATE_DETACHED;
926         detachee->joiner->broadcast();
927     }
928     
929     // Dispose of any dead threads
930     pthread_reap();
931     
932     pthread_mutex.unlock();
933
934     PTHREAD_RETURN(ret);
935 }
936
937
938 //-----------------------------------------------------------------------------
939 // Thread attribute handling.
940
941 //-----------------------------------------------------------------------------
942 // Initialize attributes object with default attributes:
943 // detachstate          == PTHREAD_CREATE_JOINABLE
944 // scope                == PTHREAD_SCOPE_SYSTEM
945 // inheritsched         == PTHREAD_INHERIT_SCHED
946 // schedpolicy          == SCHED_OTHER
947 // schedparam           == unset
948 // stackaddr            == unset
949 // stacksize            == 0
950 // 
951
952 externC int pthread_attr_init (pthread_attr_t *attr)
953 {
954     PTHREAD_ENTRY();
955     
956     PTHREAD_CHECK(attr);
957     
958     attr->detachstate                 = PTHREAD_CREATE_JOINABLE;
959     attr->scope                       = PTHREAD_SCOPE_SYSTEM;
960     attr->inheritsched                = PTHREAD_INHERIT_SCHED;
961     attr->schedpolicy                 = SCHED_OTHER;
962     attr->schedparam.sched_priority   = 0;
963     attr->stackaddr_valid             = 0;    
964     attr->stackaddr                   = NULL;
965     attr->stacksize_valid             = 0;    
966     attr->stacksize                   = 0;
967     
968     PTHREAD_RETURN(0);
969 }
970
971 //-----------------------------------------------------------------------------
972 // Destroy thread attributes object
973
974 externC int pthread_attr_destroy (pthread_attr_t *attr)
975 {
976     PTHREAD_ENTRY();
977     
978     PTHREAD_CHECK(attr);
979
980     // Nothing to do here...
981     
982     PTHREAD_RETURN(0);
983 }
984
985 //-----------------------------------------------------------------------------
986 // Set the detachstate attribute
987
988 externC int pthread_attr_setdetachstate (pthread_attr_t *attr,
989                                          int detachstate)
990 {
991     PTHREAD_ENTRY();
992     
993     PTHREAD_CHECK(attr);
994
995     if( detachstate == PTHREAD_CREATE_JOINABLE ||
996         detachstate == PTHREAD_CREATE_DETACHED )
997     {
998         attr->detachstate = detachstate;
999         PTHREAD_RETURN(0);
1000     }
1001     
1002     PTHREAD_RETURN(EINVAL);
1003 }
1004
1005 //-----------------------------------------------------------------------------
1006 // Get the detachstate attribute
1007 externC int pthread_attr_getdetachstate (const pthread_attr_t *attr,
1008                                          int *detachstate)
1009 {
1010     PTHREAD_ENTRY();
1011     
1012     PTHREAD_CHECK(attr);
1013
1014     if( detachstate != NULL )
1015         *detachstate = attr->detachstate;
1016     
1017     PTHREAD_RETURN(0);
1018 }
1019
1020 //-----------------------------------------------------------------------------
1021 // Set scheduling contention scope
1022
1023 externC int pthread_attr_setscope (pthread_attr_t *attr, int scope)
1024 {
1025     PTHREAD_ENTRY();
1026     
1027     PTHREAD_CHECK(attr);
1028
1029     if( scope == PTHREAD_SCOPE_SYSTEM ||
1030         scope == PTHREAD_SCOPE_PROCESS )
1031     {
1032         if( scope == PTHREAD_SCOPE_PROCESS )
1033             PTHREAD_RETURN(ENOTSUP);
1034
1035         attr->scope = scope;
1036
1037         PTHREAD_RETURN(0);
1038     }
1039     
1040     PTHREAD_RETURN(EINVAL);
1041 }
1042
1043 //-----------------------------------------------------------------------------
1044 // Get scheduling contention scope
1045
1046 externC int pthread_attr_getscope (const pthread_attr_t *attr, int *scope)
1047 {
1048     PTHREAD_ENTRY();
1049     
1050     PTHREAD_CHECK(attr);
1051
1052     if( scope != NULL )
1053         *scope = attr->scope;
1054     
1055     PTHREAD_RETURN(0);
1056 }
1057
1058 //-----------------------------------------------------------------------------
1059 // Set scheduling inheritance attribute
1060
1061 externC int pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit)
1062 {
1063     PTHREAD_ENTRY();
1064     
1065     PTHREAD_CHECK(attr);
1066
1067     if( inherit == PTHREAD_INHERIT_SCHED ||
1068         inherit == PTHREAD_EXPLICIT_SCHED )
1069     {
1070         attr->inheritsched = inherit;
1071
1072         PTHREAD_RETURN(0);
1073     }
1074
1075     PTHREAD_RETURN(EINVAL);
1076 }
1077
1078 //-----------------------------------------------------------------------------
1079 // Get scheduling inheritance attribute
1080
1081 externC int pthread_attr_getinheritsched (const pthread_attr_t *attr,
1082                                           int *inherit)
1083 {
1084     PTHREAD_ENTRY();
1085     
1086     PTHREAD_CHECK(attr);
1087
1088     if( inherit != NULL )
1089         *inherit = attr->inheritsched;
1090     
1091     PTHREAD_RETURN(0);
1092 }
1093
1094 //-----------------------------------------------------------------------------
1095 // Set scheduling policy
1096
1097 externC int pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
1098 {
1099     PTHREAD_ENTRY();
1100     
1101     PTHREAD_CHECK(attr);
1102
1103     if( policy == SCHED_OTHER ||
1104         policy == SCHED_FIFO ||
1105         policy == SCHED_RR )
1106     {
1107         attr->schedpolicy = policy;
1108
1109         PTHREAD_RETURN(0);
1110     }
1111     
1112     PTHREAD_RETURN(EINVAL);
1113 }
1114
1115 //-----------------------------------------------------------------------------
1116 // Get scheduling policy
1117
1118 externC int pthread_attr_getschedpolicy (const pthread_attr_t *attr,
1119                                          int *policy)
1120 {
1121     PTHREAD_ENTRY();
1122     
1123     PTHREAD_CHECK(attr);
1124
1125     if( policy != NULL )
1126         *policy = attr->schedpolicy;
1127     
1128     PTHREAD_RETURN(0);
1129 }
1130
1131 //-----------------------------------------------------------------------------
1132 // Set scheduling parameters
1133 externC int pthread_attr_setschedparam (pthread_attr_t *attr,
1134                                         const struct sched_param *param)
1135 {
1136     PTHREAD_ENTRY();
1137     
1138     PTHREAD_CHECK(attr);
1139     PTHREAD_CHECK(param);
1140
1141     attr->schedparam = *param;
1142     
1143     PTHREAD_RETURN(0);
1144 }
1145
1146 //-----------------------------------------------------------------------------
1147 // Get scheduling parameters
1148
1149 externC int pthread_attr_getschedparam (const pthread_attr_t *attr,
1150                                         struct sched_param *param)
1151 {
1152     PTHREAD_ENTRY();
1153     
1154     PTHREAD_CHECK(attr);
1155
1156     if( param != NULL )
1157         *param = attr->schedparam;
1158     
1159     PTHREAD_RETURN(0);
1160 }
1161
1162 //-----------------------------------------------------------------------------
1163 // Set starting address of stack. Whether this is at the start or end of
1164 // the memory block allocated for the stack depends on whether the stack
1165 // grows up or down.
1166
1167 externC int pthread_attr_setstackaddr (pthread_attr_t *attr, void *stackaddr)
1168 {
1169     PTHREAD_ENTRY();
1170     
1171     PTHREAD_CHECK(attr);
1172
1173     attr->stackaddr       = stackaddr;
1174     attr->stackaddr_valid = 1;
1175     
1176     PTHREAD_RETURN(0);
1177 }
1178
1179 //-----------------------------------------------------------------------------
1180 // Get any previously set stack address.
1181
1182 externC int pthread_attr_getstackaddr (const pthread_attr_t *attr,
1183                                        void **stackaddr)
1184 {
1185     PTHREAD_ENTRY();
1186     
1187     PTHREAD_CHECK(attr);
1188
1189     if( stackaddr != NULL )
1190     {
1191         if( attr->stackaddr_valid )
1192         {
1193             *stackaddr = attr->stackaddr;
1194             PTHREAD_RETURN(0);
1195         }
1196         // Stack address not set, return EINVAL.
1197         else PTHREAD_RETURN(EINVAL);
1198     }
1199
1200     PTHREAD_RETURN(0);
1201 }
1202
1203
1204 //-----------------------------------------------------------------------------
1205 // Set minimum creation stack size.
1206
1207 externC int pthread_attr_setstacksize (pthread_attr_t *attr,
1208                                        size_t stacksize)
1209 {
1210     PTHREAD_ENTRY();
1211     
1212     PTHREAD_CHECK(attr);
1213
1214     CYG_ASSERT( stacksize >= PTHREAD_STACK_MIN, "Inadequate stack size supplied");
1215     
1216     // Reject inadequate stack sizes
1217     if( stacksize < PTHREAD_STACK_MIN )
1218         PTHREAD_RETURN(EINVAL);
1219         
1220     attr->stacksize_valid = 1;    
1221     attr->stacksize = stacksize;
1222     
1223     PTHREAD_RETURN(0);
1224 }
1225
1226 //-----------------------------------------------------------------------------
1227 // Get current minimal stack size.
1228
1229 externC int pthread_attr_getstacksize (const pthread_attr_t *attr,
1230                                        size_t *stacksize)
1231 {
1232     PTHREAD_ENTRY();
1233     
1234     PTHREAD_CHECK(attr);
1235
1236     // Reject attempts to get a stack size when one has not been set.
1237     if( !attr->stacksize_valid )
1238         PTHREAD_RETURN(EINVAL);
1239     
1240     if( stacksize != NULL )
1241         *stacksize = attr->stacksize;
1242     
1243     PTHREAD_RETURN(0);
1244 }
1245
1246 //-----------------------------------------------------------------------------
1247 // Thread scheduling controls
1248
1249 //-----------------------------------------------------------------------------
1250 // Set scheduling policy and parameters for the thread
1251
1252 externC int pthread_setschedparam (pthread_t thread_id,
1253                                    int policy,
1254                                    const struct sched_param *param)
1255 {
1256     PTHREAD_ENTRY();
1257
1258     if( policy != SCHED_OTHER &&
1259         policy != SCHED_FIFO &&
1260         policy != SCHED_RR )
1261         PTHREAD_RETURN(EINVAL);
1262
1263     PTHREAD_CHECK(param);
1264
1265     // The parameters seem OK, change the thread...
1266     
1267     pthread_mutex.lock();
1268
1269     pthread_info *thread = pthread_info_id( thread_id );
1270
1271     if( thread == NULL )
1272     {
1273         pthread_mutex.unlock();
1274         PTHREAD_RETURN(ESRCH);
1275     }
1276     
1277     thread->attr.schedpolicy = policy;
1278     thread->attr.schedparam = *param;
1279
1280     if ( policy == SCHED_FIFO )
1281          thread->thread->timeslice_disable();
1282     else thread->thread->timeslice_enable();
1283
1284     thread->thread->set_priority( PTHREAD_ECOS_PRIORITY( param->sched_priority ));
1285
1286     pthread_mutex.unlock();
1287     
1288     PTHREAD_RETURN(0);
1289 }
1290
1291 //-----------------------------------------------------------------------------
1292 // Get scheduling policy and parameters for the thread
1293
1294 externC int pthread_getschedparam (pthread_t thread_id,
1295                                    int *policy,
1296                                    struct sched_param *param)
1297 {
1298     PTHREAD_ENTRY();
1299
1300     pthread_mutex.lock();
1301
1302     pthread_info *thread = pthread_info_id( thread_id );
1303
1304     if( thread == NULL )
1305     {
1306         pthread_mutex.unlock();
1307         PTHREAD_RETURN(ESRCH);
1308     }
1309
1310     if( policy != NULL )
1311         *policy = thread->attr.schedpolicy;
1312
1313     if( param != NULL )
1314         *param = thread->attr.schedparam;
1315     
1316     pthread_mutex.unlock();
1317     
1318     PTHREAD_RETURN(0);
1319 }
1320
1321
1322 //=============================================================================
1323 // Dynamic package initialization
1324 // Call init_routine just the once per control variable.
1325
1326 externC int pthread_once (pthread_once_t *once_control,
1327                           void (*init_routine) (void))
1328 {
1329     PTHREAD_ENTRY();
1330
1331     PTHREAD_CHECK( once_control );
1332     PTHREAD_CHECK( init_routine );
1333
1334     pthread_once_t old;
1335
1336     // Do a test and set on the once_control object.
1337     pthread_mutex.lock();
1338
1339     old = *once_control;
1340     *once_control = 1;
1341
1342     pthread_mutex.unlock();
1343
1344     // If the once_control was zero, call the init_routine().
1345     if( !old ) init_routine();
1346     
1347     PTHREAD_RETURN(0);
1348 }
1349
1350
1351 //=============================================================================
1352 //Thread specific data
1353
1354 //-----------------------------------------------------------------------------
1355 // Create a key to identify a location in the thread specific data area.
1356 // Each thread has its own distinct thread-specific data area but all are
1357 // addressed by the same keys. The destructor function is called whenever a
1358 // thread exits and the value associated with the key is non-NULL.
1359
1360 externC int pthread_key_create (pthread_key_t *key,
1361                                 void (*destructor) (void *))
1362 {
1363     PTHREAD_ENTRY();
1364
1365     pthread_key_t k = -1;
1366     
1367     pthread_mutex.lock();
1368
1369     // Find a key to allocate
1370     for( cyg_ucount32 i = 0; i < (PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE); i++ )
1371     {
1372         if( thread_key[i] != 0 )
1373         {
1374             // We have a table slot with space available
1375
1376             // Get index of ls set bit.
1377             HAL_LSBIT_INDEX( k, thread_key[i] );
1378
1379             // clear it
1380             thread_key[i] &= ~(1<<k);
1381
1382             // Add index of word
1383             k += i * KEY_MAP_TYPE_SIZE;
1384
1385             // Install destructor
1386             key_destructor[k] = destructor;
1387             
1388             // break out with key found
1389             break;
1390         }
1391     }
1392
1393     if( k != -1 )
1394     {
1395         // plant a NULL in all the valid thread data slots for this
1396         // key in case we are reusing a key we used before.
1397         
1398         for( cyg_ucount32 i = 0; i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
1399         {
1400             pthread_info *thread = thread_table[i];
1401
1402             if( thread != NULL && thread->thread_data != NULL )
1403                 thread->thread_data[k] = NULL;
1404         }
1405     }
1406     
1407     pthread_mutex.unlock();    
1408
1409     if( k == -1 ) PTHREAD_RETURN(EAGAIN);
1410
1411     *key = k;
1412     
1413     PTHREAD_RETURN(0);
1414 }
1415
1416 //-----------------------------------------------------------------------------
1417 // Delete key.
1418
1419 externC int pthread_key_delete (pthread_key_t key)
1420 {
1421     PTHREAD_ENTRY();
1422
1423     pthread_mutex.lock();
1424
1425     // Set the key bit to 1 to indicate it is free.
1426     thread_key[key/KEY_MAP_TYPE_SIZE] |= 1<<(key%(KEY_MAP_TYPE_SIZE));
1427
1428     pthread_mutex.unlock();        
1429     
1430     PTHREAD_RETURN(0);
1431 }
1432
1433 //-----------------------------------------------------------------------------
1434 // Store the pointer value in the thread-specific data slot addressed
1435 // by the key.
1436
1437 externC int pthread_setspecific (pthread_key_t key, const void *pointer)
1438 {
1439     PTHREAD_ENTRY();
1440
1441     if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
1442         PTHREAD_RETURN(EINVAL);
1443
1444     pthread_info *self = pthread_self_info();
1445
1446     if( self->thread_data == NULL )
1447     {
1448         // Allocate the per-thread data table
1449         self->thread_data =
1450             (void **)self->thread->increment_stack_limit(
1451                 PTHREAD_KEYS_MAX * sizeof(void *) );
1452
1453         // Clear out all entries
1454         for( int i  = 0; i < PTHREAD_KEYS_MAX; i++ )
1455             self->thread_data[i] = NULL;
1456     }
1457     
1458     self->thread_data[key] = (void *)pointer;
1459     
1460     PTHREAD_RETURN(0);
1461 }
1462
1463 //-----------------------------------------------------------------------------
1464 // Retrieve the pointer value in the thread-specific data slot addressed
1465 // by the key.
1466
1467 externC void *pthread_getspecific (pthread_key_t key)
1468 {
1469     void *val;
1470     PTHREAD_ENTRY();
1471
1472     if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
1473         PTHREAD_RETURN(NULL);
1474
1475     pthread_info *self = pthread_self_info();
1476
1477     if( self->thread_data == NULL )
1478         val = NULL;
1479     else val = self->thread_data[key];
1480
1481     PTHREAD_RETURN(val);
1482 }
1483
1484 //=============================================================================
1485 // Thread Cancellation Functions
1486
1487 //-----------------------------------------------------------------------------
1488 // Set cancel state of current thread to ENABLE or DISABLE.
1489 // Returns old state in *oldstate.
1490
1491 externC int pthread_setcancelstate (int state, int *oldstate)
1492 {
1493     PTHREAD_ENTRY();
1494
1495     if( state != PTHREAD_CANCEL_ENABLE &&
1496         state != PTHREAD_CANCEL_DISABLE )
1497         PTHREAD_RETURN(EINVAL);
1498     
1499     pthread_mutex.lock();
1500
1501     pthread_info *self = pthread_self_info();
1502
1503     if( oldstate != NULL ) *oldstate = self->cancelstate;
1504     
1505     self->cancelstate = state;
1506     
1507     pthread_mutex.unlock();
1508     
1509     // Note: This function may have made it possible for a pending
1510     // cancellation to now be delivered. However the standard does not
1511     // list this function as a cancellation point, so for now we do
1512     // nothing. In future we might call pthread_testcancel() here.
1513     
1514     PTHREAD_RETURN(0);
1515 }
1516
1517 //-----------------------------------------------------------------------------
1518 // Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
1519 // Returns old type in *oldtype.
1520
1521 externC int pthread_setcanceltype (int type, int *oldtype)
1522 {
1523     PTHREAD_ENTRY();
1524
1525     if( type != PTHREAD_CANCEL_ASYNCHRONOUS &&
1526         type != PTHREAD_CANCEL_DEFERRED )
1527         PTHREAD_RETURN(EINVAL);
1528     
1529     pthread_mutex.lock();
1530
1531     pthread_info *self = pthread_self_info();
1532         
1533     if( oldtype != NULL ) *oldtype = self->canceltype;
1534
1535     self->canceltype = type;
1536     
1537     pthread_mutex.unlock();   
1538
1539     // Note: This function may have made it possible for a pending
1540     // cancellation to now be delivered. However the standard does not
1541     // list this function as a cancellation point, so for now we do
1542     // nothing. In future we might call pthread_testcancel() here.
1543     
1544     PTHREAD_RETURN(0);
1545 }
1546
1547 //-----------------------------------------------------------------------------
1548 // Cancel the thread.
1549
1550 externC int pthread_cancel (pthread_t thread)
1551 {
1552     PTHREAD_ENTRY();
1553
1554     pthread_mutex.lock();
1555
1556     pthread_info *th = pthread_info_id(thread);
1557
1558     if( th == NULL )
1559     {
1560         pthread_mutex.unlock();
1561         PTHREAD_RETURN(ESRCH);
1562     }
1563
1564     th->cancelpending = true;
1565
1566     if ( th->cancelstate == PTHREAD_CANCEL_ENABLE )
1567     {
1568         if ( th->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS )
1569         {
1570             // If the thread has cancellation enabled, and it is in
1571             // asynchronous mode, set the eCos thread's ASR pending to
1572             // deal with it when the thread wakes up. We also release the
1573             // thread out of any current wait to make it wake up.
1574         
1575             th->thread->set_asr_pending();
1576             th->thread->release();
1577         }
1578         else if ( th->canceltype == PTHREAD_CANCEL_DEFERRED )
1579         {
1580             // If the thread has cancellation enabled, and it is in 
1581             // deferred mode, wake the thread up so that cancellation
1582             // points can test for cancellation.
1583             th->thread->release();
1584         }
1585         else
1586             CYG_FAIL("Unknown cancellation type");
1587     }
1588
1589     // Otherwise the thread has cancellation disabled, in which case
1590     // it is up to the thread to enable cancellation
1591     
1592     pthread_mutex.unlock();   
1593    
1594     
1595     PTHREAD_RETURN(0);
1596 }
1597
1598 //-----------------------------------------------------------------------------
1599 // Test for a pending cancellation for the current thread and terminate
1600 // the thread if there is one.
1601
1602 externC void pthread_testcancel (void)
1603 {
1604     PTHREAD_ENTRY_VOID();
1605
1606     if( checkforcancel() )
1607     {
1608         // If we have cancellation enabled, and there is a cancellation
1609         // pending, then go ahead and do the deed. 
1610         
1611         // Exit now with special retval. pthread_exit() calls the
1612         // cancellation handlers implicitly.
1613         pthread_exit(PTHREAD_CANCELED);
1614     }
1615         
1616     PTHREAD_RETURN_VOID;
1617 }
1618
1619 //-----------------------------------------------------------------------------
1620 // These two functions actually implement the cleanup push and pop functionality.
1621
1622 externC void pthread_cleanup_push_inner (struct pthread_cleanup_buffer *buffer,
1623                                          void (*routine) (void *),
1624                                          void *arg)
1625 {
1626     PTHREAD_ENTRY();
1627
1628     pthread_info *self = pthread_self_info();
1629
1630     buffer->routine     = routine;
1631     buffer->arg         = arg;
1632     
1633     buffer->prev        = self->cancelbuffer;
1634
1635     self->cancelbuffer  = buffer;
1636
1637     return;
1638 }
1639
1640 externC void pthread_cleanup_pop_inner (struct pthread_cleanup_buffer *buffer,
1641                                         int execute)
1642 {
1643     PTHREAD_ENTRY();
1644
1645     pthread_info *self = pthread_self_info();
1646     
1647     CYG_ASSERT( self->cancelbuffer == buffer, "Stacking error in cleanup buffers");
1648     
1649     if( self->cancelbuffer == buffer )
1650     {
1651         // Remove the buffer from the stack
1652         self->cancelbuffer = buffer->prev;
1653     }
1654     else
1655     {
1656         // If the top of the stack is not the buffer we expect, do not
1657         // execute it.
1658         execute = 0;
1659     }
1660
1661     if( execute ) buffer->routine(buffer->arg);
1662     
1663     return;
1664 }
1665
1666
1667 // -------------------------------------------------------------------------
1668 // eCos-specific function to measure stack usage of the supplied thread
1669
1670 #ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
1671 externC size_t pthread_measure_stack_usage (pthread_t thread)
1672 {
1673     pthread_info *th = pthread_info_id(thread);
1674
1675     if ( NULL == th )
1676       return (size_t)-1;
1677
1678     return (size_t)th->thread->measure_stack_usage();
1679 }
1680 #endif
1681
1682 // -------------------------------------------------------------------------
1683 // EOF pthread.cxx