]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/compat/posix/v2_0/src/pthread.cxx
Initial revision
[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                      name,
640                      stackbase,
641                      stacksize);
642
643     // Put pointer to pthread_info into eCos thread's per-thread data.
644     nthread->thread->set_data( CYGNUM_KERNEL_THREADS_DATA_POSIX, (CYG_ADDRWORD)nthread );
645
646     // Set timeslice enable according to scheduling policy.
647     if( use_attr.schedpolicy == SCHED_FIFO )
648          nthread->thread->timeslice_disable();
649     else nthread->thread->timeslice_enable();
650
651     // set up ASR and data
652     nthread->thread->set_asr( posix_asr, (CYG_ADDRWORD)nthread, NULL, NULL );    
653     
654     // return thread ID
655     *thread = nthread->id;
656
657     pthread_count++;
658                 
659     pthread_mutex.unlock();
660
661     // finally, set the thread going
662     nthread->thread->resume();
663     
664     PTHREAD_RETURN(0);
665 }
666
667 //-----------------------------------------------------------------------------
668 // Get current thread id.
669
670 externC pthread_t pthread_self ( void )
671 {
672     PTHREAD_ENTRY();
673     
674     pthread_info *info = pthread_self_info();
675
676     CYG_CHECK_DATA_PTR(info, "Not a POSIX thread!!!");
677     
678     return info->id;
679 }
680
681 //-----------------------------------------------------------------------------
682 // Compare two thread identifiers.
683
684 externC int pthread_equal (pthread_t thread1, pthread_t thread2)
685 {
686     PTHREAD_ENTRY();
687     
688     return thread1 == thread2;
689 }
690
691 //-----------------------------------------------------------------------------
692 // Terminate current thread.
693
694 externC void exit(int) CYGBLD_ATTRIB_NORET;
695
696 externC void pthread_exit (void *retval)
697 {
698     PTHREAD_ENTRY();
699     
700     pthread_info *self = pthread_self_info();
701
702     // Disable cancellation requests for this thread.  If cleanup
703     // handlers exist, they will generally be issuing system calls
704     // to clean up resources.  We want these system calls to run
705     // without cancelling, and we also want to prevent being
706     // re-cancelled.
707     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
708
709     // Call cancellation handlers. We eat up the buffers as we go in
710     // case any of the routines calls pthread_exit() itself.
711     while( self->cancelbuffer != NULL )
712     {
713         struct pthread_cleanup_buffer *buffer = self->cancelbuffer;
714
715         self->cancelbuffer = buffer->prev;
716
717         buffer->routine(buffer->arg);
718     }
719
720     if( self->thread_data != NULL )
721     {
722         // Call per-thread key destructors.
723         // The specification of this is that we must continue to call the
724         // destructor functions until all the per-thread data values are NULL or
725         // we have done it PTHREAD_DESTRUCTOR_ITERATIONS times.
726     
727         cyg_bool destructors_called;
728         int destructor_iterations = 0;
729
730         do
731         {
732             destructors_called = false;
733         
734             for( cyg_ucount32 key = 0; key < PTHREAD_KEYS_MAX; key++ )
735             {
736                 // Skip unallocated keys
737                 if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
738                     continue;
739
740                 // Skip NULL destructors
741                 if( key_destructor[key] == NULL ) continue;
742
743                 // Skip NULL data values
744                 if( self->thread_data[key] == NULL ) continue;
745
746                 // If it passes all that, call the destructor.
747                 // Note that NULLing the data value here is new
748                 // behaviour in the 2001 POSIX standard.
749                 {
750                     void* value = self->thread_data[key];
751                     self->thread_data[key] = NULL;
752                     key_destructor[key](value);
753                 }
754
755                 // Record that we called a destructor
756                 destructors_called = true;
757             }
758
759             // Count the iteration
760             destructor_iterations++;
761         
762         } while( destructors_called &&
763                  (destructor_iterations <= PTHREAD_DESTRUCTOR_ITERATIONS));
764
765     }
766     
767     pthread_mutex.lock();
768
769     // Set the retval for any joiner
770     self->retval = retval;
771
772     // If we are already detached, go to EXITED state, otherwise
773     // go into JOIN state.
774     
775     if ( PTHREAD_STATE_DETACHED == self->state ) {
776         self->state = PTHREAD_STATE_EXITED;
777         pthreads_exited++;
778     } else {
779         self->state = PTHREAD_STATE_JOIN;
780         pthreads_tobejoined++;
781     }
782
783     // Kick any waiting joiners
784     self->joiner->broadcast();
785
786     cyg_bool call_exit=false;
787
788     // if this is the last thread (other than threads waiting to be joined)
789     // then we need to call exit() later
790     if ( pthreads_exited + pthreads_tobejoined == pthread_count )
791         call_exit=true;
792
793     pthread_mutex.unlock();
794     
795     // Finally, call the exit function; this will not return.
796     if ( call_exit )
797         ::exit(0);
798     else
799         self->thread->exit();
800
801     // This loop keeps some compilers happy. pthread_exit() is marked
802     // with the noreturn attribute, and without this they generate a
803     // call to abort() here in case Cyg_Thread::exit() returns. 
804     
805     for(;;) continue;
806 }
807
808 //-----------------------------------------------------------------------------
809 // Wait for the thread to terminate. If thread_return is not NULL then
810 // the retval from the thread's call to pthread_exit() is stored at
811 // *thread_return.
812
813 externC int pthread_join (pthread_t thread, void **thread_return)
814 {
815     int err = 0;
816
817     PTHREAD_ENTRY();
818     
819     // check for cancellation first.
820     pthread_testcancel();
821
822     pthread_mutex.lock();
823     
824     // Dispose of any dead threads
825     pthread_reap();
826     
827     pthread_info *self = pthread_self_info();
828     pthread_info *joinee = pthread_info_id( thread );
829
830     if( joinee == NULL )
831     {
832         err = ESRCH;
833     }
834
835     if( !err && joinee == self )
836     {
837         err = EDEADLK;
838     }
839
840     if ( !err ) {
841         switch ( joinee->state )
842         {
843         case PTHREAD_STATE_RUNNING:
844             // The thread is still running, we must wait for it.
845         while( joinee->state == PTHREAD_STATE_RUNNING ) {
846             if ( !joinee->joiner->wait() )
847                 // check if we were woken because we were being cancelled
848                 if ( checkforcancel() ) {
849                     err = EAGAIN;  // value unimportant, just some error
850                     break;
851                 }
852         }
853
854         // check that the thread is still joinable
855         if( joinee->state == PTHREAD_STATE_JOIN )
856             break;
857
858         // The thread has become unjoinable while we waited, so we
859         // fall through to complain.
860         
861         case PTHREAD_STATE_FREE:
862         case PTHREAD_STATE_DETACHED:
863         case PTHREAD_STATE_EXITED:
864         // None of these may be joined.
865             err = EINVAL;
866             break;
867             
868         case PTHREAD_STATE_JOIN:
869             break;
870         }
871     }
872
873     if ( !err ) {
874     
875         // here, we know that joinee is a thread that has exited and is
876         // ready to be joined.
877
878         // Get the retval
879         if( thread_return != NULL )
880             *thread_return = joinee->retval;
881         
882         // set state to exited.
883         joinee->state = PTHREAD_STATE_EXITED;
884         pthreads_exited++;
885         pthreads_tobejoined--;
886     
887         // Dispose of any dead threads
888         pthread_reap();
889     }
890
891     pthread_mutex.unlock();
892     
893     // check for cancellation before returning
894     pthread_testcancel();
895
896     PTHREAD_RETURN(err);
897 }
898
899 //-----------------------------------------------------------------------------
900 // Set the detachstate of the thread to "detached". The thread then does not
901 // need to be joined and its resources will be freed when it exits.
902
903 externC int pthread_detach (pthread_t thread)
904 {
905     PTHREAD_ENTRY();
906     
907     int ret = 0;
908     
909     pthread_mutex.lock();
910
911     pthread_info *detachee = pthread_info_id( thread );
912     
913     if( detachee == NULL )
914         ret = ESRCH;                    // No such thread
915     else if( detachee->state == PTHREAD_STATE_DETACHED )
916         ret = EINVAL;                   // Already detached!
917     else
918     {
919         // Set state to detached and kick any joinees to
920         // make them return.
921         detachee->state = PTHREAD_STATE_DETACHED;
922         detachee->joiner->broadcast();
923     }
924     
925     // Dispose of any dead threads
926     pthread_reap();
927     
928     pthread_mutex.unlock();
929
930     PTHREAD_RETURN(ret);
931 }
932
933
934 //-----------------------------------------------------------------------------
935 // Thread attribute handling.
936
937 //-----------------------------------------------------------------------------
938 // Initialize attributes object with default attributes:
939 // detachstate          == PTHREAD_CREATE_JOINABLE
940 // scope                == PTHREAD_SCOPE_SYSTEM
941 // inheritsched         == PTHREAD_INHERIT_SCHED
942 // schedpolicy          == SCHED_OTHER
943 // schedparam           == unset
944 // stackaddr            == unset
945 // stacksize            == 0
946 // 
947
948 externC int pthread_attr_init (pthread_attr_t *attr)
949 {
950     PTHREAD_ENTRY();
951     
952     PTHREAD_CHECK(attr);
953     
954     attr->detachstate                 = PTHREAD_CREATE_JOINABLE;
955     attr->scope                       = PTHREAD_SCOPE_SYSTEM;
956     attr->inheritsched                = PTHREAD_INHERIT_SCHED;
957     attr->schedpolicy                 = SCHED_OTHER;
958     attr->schedparam.sched_priority   = 0;
959     attr->stackaddr_valid             = 0;    
960     attr->stackaddr                   = NULL;
961     attr->stacksize_valid             = 0;    
962     attr->stacksize                   = 0;
963     
964     PTHREAD_RETURN(0);
965 }
966
967 //-----------------------------------------------------------------------------
968 // Destroy thread attributes object
969
970 externC int pthread_attr_destroy (pthread_attr_t *attr)
971 {
972     PTHREAD_ENTRY();
973     
974     PTHREAD_CHECK(attr);
975
976     // Nothing to do here...
977     
978     PTHREAD_RETURN(0);
979 }
980
981 //-----------------------------------------------------------------------------
982 // Set the detachstate attribute
983
984 externC int pthread_attr_setdetachstate (pthread_attr_t *attr,
985                                          int detachstate)
986 {
987     PTHREAD_ENTRY();
988     
989     PTHREAD_CHECK(attr);
990
991     if( detachstate == PTHREAD_CREATE_JOINABLE ||
992         detachstate == PTHREAD_CREATE_DETACHED )
993     {
994         attr->detachstate = detachstate;
995         PTHREAD_RETURN(0);
996     }
997     
998     PTHREAD_RETURN(EINVAL);
999 }
1000
1001 //-----------------------------------------------------------------------------
1002 // Get the detachstate attribute
1003 externC int pthread_attr_getdetachstate (const pthread_attr_t *attr,
1004                                          int *detachstate)
1005 {
1006     PTHREAD_ENTRY();
1007     
1008     PTHREAD_CHECK(attr);
1009
1010     if( detachstate != NULL )
1011         *detachstate = attr->detachstate;
1012     
1013     PTHREAD_RETURN(0);
1014 }
1015
1016 //-----------------------------------------------------------------------------
1017 // Set scheduling contention scope
1018
1019 externC int pthread_attr_setscope (pthread_attr_t *attr, int scope)
1020 {
1021     PTHREAD_ENTRY();
1022     
1023     PTHREAD_CHECK(attr);
1024
1025     if( scope == PTHREAD_SCOPE_SYSTEM ||
1026         scope == PTHREAD_SCOPE_PROCESS )
1027     {
1028         if( scope == PTHREAD_SCOPE_PROCESS )
1029             PTHREAD_RETURN(ENOTSUP);
1030
1031         attr->scope = scope;
1032
1033         PTHREAD_RETURN(0);
1034     }
1035     
1036     PTHREAD_RETURN(EINVAL);
1037 }
1038
1039 //-----------------------------------------------------------------------------
1040 // Get scheduling contention scope
1041
1042 externC int pthread_attr_getscope (const pthread_attr_t *attr, int *scope)
1043 {
1044     PTHREAD_ENTRY();
1045     
1046     PTHREAD_CHECK(attr);
1047
1048     if( scope != NULL )
1049         *scope = attr->scope;
1050     
1051     PTHREAD_RETURN(0);
1052 }
1053
1054 //-----------------------------------------------------------------------------
1055 // Set scheduling inheritance attribute
1056
1057 externC int pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit)
1058 {
1059     PTHREAD_ENTRY();
1060     
1061     PTHREAD_CHECK(attr);
1062
1063     if( inherit == PTHREAD_INHERIT_SCHED ||
1064         inherit == PTHREAD_EXPLICIT_SCHED )
1065     {
1066         attr->inheritsched = inherit;
1067
1068         PTHREAD_RETURN(0);
1069     }
1070
1071     PTHREAD_RETURN(EINVAL);
1072 }
1073
1074 //-----------------------------------------------------------------------------
1075 // Get scheduling inheritance attribute
1076
1077 externC int pthread_attr_getinheritsched (const pthread_attr_t *attr,
1078                                           int *inherit)
1079 {
1080     PTHREAD_ENTRY();
1081     
1082     PTHREAD_CHECK(attr);
1083
1084     if( inherit != NULL )
1085         *inherit = attr->inheritsched;
1086     
1087     PTHREAD_RETURN(0);
1088 }
1089
1090 //-----------------------------------------------------------------------------
1091 // Set scheduling policy
1092
1093 externC int pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
1094 {
1095     PTHREAD_ENTRY();
1096     
1097     PTHREAD_CHECK(attr);
1098
1099     if( policy == SCHED_OTHER ||
1100         policy == SCHED_FIFO ||
1101         policy == SCHED_RR )
1102     {
1103         attr->schedpolicy = policy;
1104
1105         PTHREAD_RETURN(0);
1106     }
1107     
1108     PTHREAD_RETURN(EINVAL);
1109 }
1110
1111 //-----------------------------------------------------------------------------
1112 // Get scheduling policy
1113
1114 externC int pthread_attr_getschedpolicy (const pthread_attr_t *attr,
1115                                          int *policy)
1116 {
1117     PTHREAD_ENTRY();
1118     
1119     PTHREAD_CHECK(attr);
1120
1121     if( policy != NULL )
1122         *policy = attr->schedpolicy;
1123     
1124     PTHREAD_RETURN(0);
1125 }
1126
1127 //-----------------------------------------------------------------------------
1128 // Set scheduling parameters
1129 externC int pthread_attr_setschedparam (pthread_attr_t *attr,
1130                                         const struct sched_param *param)
1131 {
1132     PTHREAD_ENTRY();
1133     
1134     PTHREAD_CHECK(attr);
1135     PTHREAD_CHECK(param);
1136
1137     attr->schedparam = *param;
1138     
1139     PTHREAD_RETURN(0);
1140 }
1141
1142 //-----------------------------------------------------------------------------
1143 // Get scheduling parameters
1144
1145 externC int pthread_attr_getschedparam (const pthread_attr_t *attr,
1146                                         struct sched_param *param)
1147 {
1148     PTHREAD_ENTRY();
1149     
1150     PTHREAD_CHECK(attr);
1151
1152     if( param != NULL )
1153         *param = attr->schedparam;
1154     
1155     PTHREAD_RETURN(0);
1156 }
1157
1158 //-----------------------------------------------------------------------------
1159 // Set starting address of stack. Whether this is at the start or end of
1160 // the memory block allocated for the stack depends on whether the stack
1161 // grows up or down.
1162
1163 externC int pthread_attr_setstackaddr (pthread_attr_t *attr, void *stackaddr)
1164 {
1165     PTHREAD_ENTRY();
1166     
1167     PTHREAD_CHECK(attr);
1168
1169     attr->stackaddr       = stackaddr;
1170     attr->stackaddr_valid = 1;
1171     
1172     PTHREAD_RETURN(0);
1173 }
1174
1175 //-----------------------------------------------------------------------------
1176 // Get any previously set stack address.
1177
1178 externC int pthread_attr_getstackaddr (const pthread_attr_t *attr,
1179                                        void **stackaddr)
1180 {
1181     PTHREAD_ENTRY();
1182     
1183     PTHREAD_CHECK(attr);
1184
1185     if( stackaddr != NULL )
1186     {
1187         if( attr->stackaddr_valid )
1188         {
1189             *stackaddr = attr->stackaddr;
1190             PTHREAD_RETURN(0);
1191         }
1192         // Stack address not set, return EINVAL.
1193         else PTHREAD_RETURN(EINVAL);
1194     }
1195
1196     PTHREAD_RETURN(0);
1197 }
1198
1199
1200 //-----------------------------------------------------------------------------
1201 // Set minimum creation stack size.
1202
1203 externC int pthread_attr_setstacksize (pthread_attr_t *attr,
1204                                        size_t stacksize)
1205 {
1206     PTHREAD_ENTRY();
1207     
1208     PTHREAD_CHECK(attr);
1209
1210     CYG_ASSERT( stacksize >= PTHREAD_STACK_MIN, "Inadequate stack size supplied");
1211     
1212     // Reject inadequate stack sizes
1213     if( stacksize < PTHREAD_STACK_MIN )
1214         PTHREAD_RETURN(EINVAL);
1215         
1216     attr->stacksize_valid = 1;    
1217     attr->stacksize = stacksize;
1218     
1219     PTHREAD_RETURN(0);
1220 }
1221
1222 //-----------------------------------------------------------------------------
1223 // Get current minimal stack size.
1224
1225 externC int pthread_attr_getstacksize (const pthread_attr_t *attr,
1226                                        size_t *stacksize)
1227 {
1228     PTHREAD_ENTRY();
1229     
1230     PTHREAD_CHECK(attr);
1231
1232     // Reject attempts to get a stack size when one has not been set.
1233     if( !attr->stacksize_valid )
1234         PTHREAD_RETURN(EINVAL);
1235     
1236     if( stacksize != NULL )
1237         *stacksize = attr->stacksize;
1238     
1239     PTHREAD_RETURN(0);
1240 }
1241
1242 //-----------------------------------------------------------------------------
1243 // Thread scheduling controls
1244
1245 //-----------------------------------------------------------------------------
1246 // Set scheduling policy and parameters for the thread
1247
1248 externC int pthread_setschedparam (pthread_t thread_id,
1249                                    int policy,
1250                                    const struct sched_param *param)
1251 {
1252     PTHREAD_ENTRY();
1253
1254     if( policy != SCHED_OTHER &&
1255         policy != SCHED_FIFO &&
1256         policy != SCHED_RR )
1257         PTHREAD_RETURN(EINVAL);
1258
1259     PTHREAD_CHECK(param);
1260
1261     // The parameters seem OK, change the thread...
1262     
1263     pthread_mutex.lock();
1264
1265     pthread_info *thread = pthread_info_id( thread_id );
1266
1267     if( thread == NULL )
1268     {
1269         pthread_mutex.unlock();
1270         PTHREAD_RETURN(ESRCH);
1271     }
1272     
1273     thread->attr.schedpolicy = policy;
1274     thread->attr.schedparam = *param;
1275
1276     if ( policy == SCHED_FIFO )
1277          thread->thread->timeslice_disable();
1278     else thread->thread->timeslice_enable();
1279
1280     thread->thread->set_priority( PTHREAD_ECOS_PRIORITY( param->sched_priority ));
1281
1282     pthread_mutex.unlock();
1283     
1284     PTHREAD_RETURN(0);
1285 }
1286
1287 //-----------------------------------------------------------------------------
1288 // Get scheduling policy and parameters for the thread
1289
1290 externC int pthread_getschedparam (pthread_t thread_id,
1291                                    int *policy,
1292                                    struct sched_param *param)
1293 {
1294     PTHREAD_ENTRY();
1295
1296     pthread_mutex.lock();
1297
1298     pthread_info *thread = pthread_info_id( thread_id );
1299
1300     if( thread == NULL )
1301     {
1302         pthread_mutex.unlock();
1303         PTHREAD_RETURN(ESRCH);
1304     }
1305
1306     if( policy != NULL )
1307         *policy = thread->attr.schedpolicy;
1308
1309     if( param != NULL )
1310         *param = thread->attr.schedparam;
1311     
1312     pthread_mutex.unlock();
1313     
1314     PTHREAD_RETURN(0);
1315 }
1316
1317
1318 //=============================================================================
1319 // Dynamic package initialization
1320 // Call init_routine just the once per control variable.
1321
1322 externC int pthread_once (pthread_once_t *once_control,
1323                           void (*init_routine) (void))
1324 {
1325     PTHREAD_ENTRY();
1326
1327     PTHREAD_CHECK( once_control );
1328     PTHREAD_CHECK( init_routine );
1329
1330     pthread_once_t old;
1331
1332     // Do a test and set on the once_control object.
1333     pthread_mutex.lock();
1334
1335     old = *once_control;
1336     *once_control = 1;
1337
1338     pthread_mutex.unlock();
1339
1340     // If the once_control was zero, call the init_routine().
1341     if( !old ) init_routine();
1342     
1343     PTHREAD_RETURN(0);
1344 }
1345
1346
1347 //=============================================================================
1348 //Thread specific data
1349
1350 //-----------------------------------------------------------------------------
1351 // Create a key to identify a location in the thread specific data area.
1352 // Each thread has its own distinct thread-specific data area but all are
1353 // addressed by the same keys. The destructor function is called whenever a
1354 // thread exits and the value associated with the key is non-NULL.
1355
1356 externC int pthread_key_create (pthread_key_t *key,
1357                                 void (*destructor) (void *))
1358 {
1359     PTHREAD_ENTRY();
1360
1361     pthread_key_t k = -1;
1362     
1363     pthread_mutex.lock();
1364
1365     // Find a key to allocate
1366     for( cyg_ucount32 i = 0; i < (PTHREAD_KEYS_MAX/KEY_MAP_TYPE_SIZE); i++ )
1367     {
1368         if( thread_key[i] != 0 )
1369         {
1370             // We have a table slot with space available
1371
1372             // Get index of ls set bit.
1373             HAL_LSBIT_INDEX( k, thread_key[i] );
1374
1375             // clear it
1376             thread_key[i] &= ~(1<<k);
1377
1378             // Add index of word
1379             k += i * KEY_MAP_TYPE_SIZE;
1380
1381             // Install destructor
1382             key_destructor[k] = destructor;
1383             
1384             // break out with key found
1385             break;
1386         }
1387     }
1388
1389     if( k != -1 )
1390     {
1391         // plant a NULL in all the valid thread data slots for this
1392         // key in case we are reusing a key we used before.
1393         
1394         for( cyg_ucount32 i = 0; i < CYGNUM_POSIX_PTHREAD_THREADS_MAX ; i++ )
1395         {
1396             pthread_info *thread = thread_table[i];
1397
1398             if( thread != NULL && thread->thread_data != NULL )
1399                 thread->thread_data[k] = NULL;
1400         }
1401     }
1402     
1403     pthread_mutex.unlock();    
1404
1405     if( k == -1 ) PTHREAD_RETURN(EAGAIN);
1406
1407     *key = k;
1408     
1409     PTHREAD_RETURN(0);
1410 }
1411
1412 //-----------------------------------------------------------------------------
1413 // Delete key.
1414
1415 externC int pthread_key_delete (pthread_key_t key)
1416 {
1417     PTHREAD_ENTRY();
1418
1419     pthread_mutex.lock();
1420
1421     // Set the key bit to 1 to indicate it is free.
1422     thread_key[key/KEY_MAP_TYPE_SIZE] |= 1<<(key%(KEY_MAP_TYPE_SIZE));
1423
1424     pthread_mutex.unlock();        
1425     
1426     PTHREAD_RETURN(0);
1427 }
1428
1429 //-----------------------------------------------------------------------------
1430 // Store the pointer value in the thread-specific data slot addressed
1431 // by the key.
1432
1433 externC int pthread_setspecific (pthread_key_t key, const void *pointer)
1434 {
1435     PTHREAD_ENTRY();
1436
1437     if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
1438         PTHREAD_RETURN(EINVAL);
1439
1440     pthread_info *self = pthread_self_info();
1441
1442     if( self->thread_data == NULL )
1443     {
1444         // Allocate the per-thread data table
1445         self->thread_data =
1446             (void **)self->thread->increment_stack_limit(
1447                 PTHREAD_KEYS_MAX * sizeof(void *) );
1448
1449         // Clear out all entries
1450         for( int i  = 0; i < PTHREAD_KEYS_MAX; i++ )
1451             self->thread_data[i] = NULL;
1452     }
1453     
1454     self->thread_data[key] = (void *)pointer;
1455     
1456     PTHREAD_RETURN(0);
1457 }
1458
1459 //-----------------------------------------------------------------------------
1460 // Retrieve the pointer value in the thread-specific data slot addressed
1461 // by the key.
1462
1463 externC void *pthread_getspecific (pthread_key_t key)
1464 {
1465     void *val;
1466     PTHREAD_ENTRY();
1467
1468     if( thread_key[key/KEY_MAP_TYPE_SIZE] & 1<<(key%KEY_MAP_TYPE_SIZE) )
1469         PTHREAD_RETURN(NULL);
1470
1471     pthread_info *self = pthread_self_info();
1472
1473     if( self->thread_data == NULL )
1474         val = NULL;
1475     else val = self->thread_data[key];
1476
1477     PTHREAD_RETURN(val);
1478 }
1479
1480 //=============================================================================
1481 // Thread Cancellation Functions
1482
1483 //-----------------------------------------------------------------------------
1484 // Set cancel state of current thread to ENABLE or DISABLE.
1485 // Returns old state in *oldstate.
1486
1487 externC int pthread_setcancelstate (int state, int *oldstate)
1488 {
1489     PTHREAD_ENTRY();
1490
1491     if( state != PTHREAD_CANCEL_ENABLE &&
1492         state != PTHREAD_CANCEL_DISABLE )
1493         PTHREAD_RETURN(EINVAL);
1494     
1495     pthread_mutex.lock();
1496
1497     pthread_info *self = pthread_self_info();
1498
1499     if( oldstate != NULL ) *oldstate = self->cancelstate;
1500     
1501     self->cancelstate = state;
1502     
1503     pthread_mutex.unlock();
1504     
1505     // Note: This function may have made it possible for a pending
1506     // cancellation to now be delivered. However the standard does not
1507     // list this function as a cancellation point, so for now we do
1508     // nothing. In future we might call pthread_testcancel() here.
1509     
1510     PTHREAD_RETURN(0);
1511 }
1512
1513 //-----------------------------------------------------------------------------
1514 // Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
1515 // Returns old type in *oldtype.
1516
1517 externC int pthread_setcanceltype (int type, int *oldtype)
1518 {
1519     PTHREAD_ENTRY();
1520
1521     if( type != PTHREAD_CANCEL_ASYNCHRONOUS &&
1522         type != PTHREAD_CANCEL_DEFERRED )
1523         PTHREAD_RETURN(EINVAL);
1524     
1525     pthread_mutex.lock();
1526
1527     pthread_info *self = pthread_self_info();
1528         
1529     if( oldtype != NULL ) *oldtype = self->canceltype;
1530
1531     self->canceltype = type;
1532     
1533     pthread_mutex.unlock();   
1534
1535     // Note: This function may have made it possible for a pending
1536     // cancellation to now be delivered. However the standard does not
1537     // list this function as a cancellation point, so for now we do
1538     // nothing. In future we might call pthread_testcancel() here.
1539     
1540     PTHREAD_RETURN(0);
1541 }
1542
1543 //-----------------------------------------------------------------------------
1544 // Cancel the thread.
1545
1546 externC int pthread_cancel (pthread_t thread)
1547 {
1548     PTHREAD_ENTRY();
1549
1550     pthread_mutex.lock();
1551
1552     pthread_info *th = pthread_info_id(thread);
1553
1554     if( th == NULL )
1555     {
1556         pthread_mutex.unlock();
1557         PTHREAD_RETURN(ESRCH);
1558     }
1559
1560     th->cancelpending = true;
1561
1562     if ( th->cancelstate == PTHREAD_CANCEL_ENABLE )
1563     {
1564         if ( th->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS )
1565         {
1566             // If the thread has cancellation enabled, and it is in
1567             // asynchronous mode, set the eCos thread's ASR pending to
1568             // deal with it when the thread wakes up. We also release the
1569             // thread out of any current wait to make it wake up.
1570         
1571             th->thread->set_asr_pending();
1572             th->thread->release();
1573         }
1574         else if ( th->canceltype == PTHREAD_CANCEL_DEFERRED )
1575         {
1576             // If the thread has cancellation enabled, and it is in 
1577             // deferred mode, wake the thread up so that cancellation
1578             // points can test for cancellation.
1579             th->thread->release();
1580         }
1581         else
1582             CYG_FAIL("Unknown cancellation type");
1583     }
1584
1585     // Otherwise the thread has cancellation disabled, in which case
1586     // it is up to the thread to enable cancellation
1587     
1588     pthread_mutex.unlock();   
1589    
1590     
1591     PTHREAD_RETURN(0);
1592 }
1593
1594 //-----------------------------------------------------------------------------
1595 // Test for a pending cancellation for the current thread and terminate
1596 // the thread if there is one.
1597
1598 externC void pthread_testcancel (void)
1599 {
1600     PTHREAD_ENTRY_VOID();
1601
1602     if( checkforcancel() )
1603     {
1604         // If we have cancellation enabled, and there is a cancellation
1605         // pending, then go ahead and do the deed. 
1606         
1607         // Exit now with special retval. pthread_exit() calls the
1608         // cancellation handlers implicitly.
1609         pthread_exit(PTHREAD_CANCELED);
1610     }
1611         
1612     PTHREAD_RETURN_VOID;
1613 }
1614
1615 //-----------------------------------------------------------------------------
1616 // These two functions actually implement the cleanup push and pop functionality.
1617
1618 externC void pthread_cleanup_push_inner (struct pthread_cleanup_buffer *buffer,
1619                                          void (*routine) (void *),
1620                                          void *arg)
1621 {
1622     PTHREAD_ENTRY();
1623
1624     pthread_info *self = pthread_self_info();
1625
1626     buffer->routine     = routine;
1627     buffer->arg         = arg;
1628     
1629     buffer->prev        = self->cancelbuffer;
1630
1631     self->cancelbuffer  = buffer;
1632
1633     return;
1634 }
1635
1636 externC void pthread_cleanup_pop_inner (struct pthread_cleanup_buffer *buffer,
1637                                         int execute)
1638 {
1639     PTHREAD_ENTRY();
1640
1641     pthread_info *self = pthread_self_info();
1642     
1643     CYG_ASSERT( self->cancelbuffer == buffer, "Stacking error in cleanup buffers");
1644     
1645     if( self->cancelbuffer == buffer )
1646     {
1647         // Remove the buffer from the stack
1648         self->cancelbuffer = buffer->prev;
1649     }
1650     else
1651     {
1652         // If the top of the stack is not the buffer we expect, do not
1653         // execute it.
1654         execute = 0;
1655     }
1656
1657     if( execute ) buffer->routine(buffer->arg);
1658     
1659     return;
1660 }
1661
1662
1663 // -------------------------------------------------------------------------
1664 // eCos-specific function to measure stack usage of the supplied thread
1665
1666 #ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
1667 externC size_t pthread_measure_stack_usage (pthread_t thread)
1668 {
1669     pthread_info *th = pthread_info_id(thread);
1670
1671     if ( NULL == th )
1672       return (size_t)-1;
1673
1674     return (size_t)th->thread->measure_stack_usage();
1675 }
1676 #endif
1677
1678 // -------------------------------------------------------------------------
1679 // EOF pthread.cxx