]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/compat/posix/v2_0/src/signal.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / compat / posix / v2_0 / src / signal.cxx
1 //==========================================================================
2 //
3 //      signal.cxx
4 //
5 //      POSIX signal functions 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 // Copyright (C) 2002 Nick Garnett
13 // Copyright (C) 2004 eCosCentric Ltd.
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 //
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //==========================================================================
43 //#####DESCRIPTIONBEGIN####
44 //
45 // Author(s):           nickg
46 // Contributors:        nickg
47 // Date:                2000-03-27
48 // Purpose:             POSIX signal functions implementation
49 // Description:         This file contains the implementation of the POSIX signal
50 //                      functions.
51 //              
52 //              
53 //
54 //####DESCRIPTIONEND####
55 //
56 //==========================================================================
57
58 #include <pkgconf/posix.h>
59
60 #ifdef CYGPKG_POSIX_SIGNALS
61
62 #include <pkgconf/hal.h>
63 #include <pkgconf/kernel.h>
64 #include <pkgconf/isoinfra.h>
65
66 #include <cyg/kernel/ktypes.h>          // base kernel types
67 #include <cyg/infra/cyg_trac.h>         // tracing macros
68 #include <cyg/infra/cyg_ass.h>          // assertion macros
69
70 #include "pprivate.h"                   // POSIX private header
71
72 #include <signal.h>                     // our header
73 #include <setjmp.h>
74 #include <unistd.h>                     // _exit
75
76 #include <cyg/kernel/clock.hxx>
77 #include <cyg/kernel/thread.hxx>
78 #include <cyg/kernel/clock.inl>
79 #include <cyg/kernel/thread.inl>
80
81 // -------------------------------------------------------------------------
82 // Internal definitions
83
84 // Handle entry to a signal package function. 
85 #define SIGNAL_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );
86
87 // Do a signal package defined return. This requires the error code
88 // to be placed in errno, and if it is non-zero, -1 returned as the
89 // result of the function. This also gives us a place to put any
90 // generic tidyup handling needed for things like signal delivery and
91 // cancellation.
92 #define SIGNAL_RETURN(err)                      \
93 CYG_MACRO_START                                 \
94     int __retval = 0;                           \
95     if( err != 0 ) __retval = -1, errno = err;  \
96     CYG_REPORT_RETVAL( __retval );              \
97     return __retval;                            \
98 CYG_MACRO_END
99
100 // Similarly for functions that have valid non-zero returns
101 #define SIGNAL_RETURN_VALUE(val)                \
102 CYG_MACRO_START                                 \
103     CYG_REPORT_RETVAL( val );                   \
104     return val;                                 \
105 CYG_MACRO_END
106
107 // Range check on a signal value.
108 #define SIGNAL_VALID(_sig_) (((_sig_) > 0) && ((_sig_) < ((int)sizeof(sigset_t)*8)))
109
110 //==========================================================================
111 // Signal management structures
112
113 typedef struct signal_info
114 {
115     struct signal_info          *next;  // link in list of pending signals
116     siginfo_t                   si;     // siginfo to pass to handler
117 } signal_info;
118
119 typedef struct
120 {
121     struct sigaction            sa;     // Sigaction defining what to do
122     signal_info                 *pending; // List of pending signals - this is
123                                           // a circular list with pending pointing
124                                           // to the tail element (or NULL if empty).
125 } signal_state;
126
127 //==========================================================================
128 // Signal management variables
129
130 // Lock used to protect signal management structures
131 Cyg_Mutex signal_mutex CYGBLD_POSIX_INIT;
132
133 // Condition variable for all threads in sigsuspend() and sigwait()
134 // to wait on.
135 Cyg_Condition_Variable CYGBLD_POSIX_INIT signal_sigwait( signal_mutex ) ;
136
137 // Global pending signal set
138 sigset_t sig_pending;
139
140 // Array controlling signal states
141 static signal_state sigstate[sizeof(sigset_t)*8];
142
143 // Array of available signal_info objects for queueing signals
144 static signal_info siginfo[SIGQUEUE_MAX];
145
146 // List of free signal_info objects
147 static signal_info *siginfo_next = NULL;
148
149 //==========================================================================
150 // Variables used to support alarm()
151
152 // Forward def of action function
153 static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data );
154
155 // Kernel alarm object
156 static Cyg_Alarm CYGBLD_POSIX_INIT sigalrm_alarm( Cyg_Clock::real_time_clock, sigalrm_action, 0 ) ;
157
158 // Set true when alarm is armed
159 volatile cyg_bool sigalrm_armed = false;
160
161 // Set true when alarm has fired and is waiting to be delivered
162 volatile cyg_bool sigalrm_pending = false;
163
164 //==========================================================================
165 // Implementation functions.
166 // These are where the real work of the signal mechanism gets done.
167
168 externC void cyg_posix_signal_start()
169 {
170     // Chain all free signal_info objects together
171     for( int i = 0; i < SIGQUEUE_MAX; i++ )
172     {
173         siginfo[i].next = siginfo_next;
174         siginfo_next = &siginfo[i];
175     }
176     
177     // initialize all signal actions to SIG_DFL
178     for ( unsigned int i=0; i<(sizeof(sigstate)/sizeof(signal_state)); i++ )
179     {
180         sigstate[i].sa.sa_handler = SIG_DFL;
181     }
182
183     // Clear the pending signal set
184     sigemptyset( &sig_pending );
185 }
186
187 // -------------------------------------------------------------------------
188 // Generate a signal
189
190 cyg_bool cyg_sigqueue( const struct sigevent *sev, int code,
191                        pthread_info *thread )
192 {
193     if( sev->sigev_notify == SIGEV_NONE )
194     {
195         // Do nothing
196         return true;
197     }
198
199     if( sev->sigev_notify == SIGEV_THREAD )
200     {
201         // create a thread to run the notification
202         // function.
203         // FIXME: implement SIGEV_THREAD
204         return true;
205     }
206
207     // Otherwise we must have a SIGEV_SIGNAL notification
208
209     // Find out whether the current thread already has the mutex
210     // locked. This is a distinct possibility if this function is
211     // called from the ASR while exiting the signal_sigwait condvar in
212     // pause() and sigtimedwait().
213     
214     pthread_info *self = pthread_self_info();
215     cyg_bool locked = (self != NULL) && (signal_mutex.get_owner() == self->thread);
216     
217     // Lock the mutex only if we do not already own it
218     if( !locked ) signal_mutex.lock();
219     
220     int signo = sev->sigev_signo;
221     signal_state *ss = &sigstate[signo];
222
223     if( ss->sa.sa_flags & SA_SIGINFO )
224     {
225         // We have a queuable signal, allocate a signal_info
226         // object and add it to the queue.
227
228         if( siginfo_next == NULL )
229         {
230             if( !locked ) signal_mutex.unlock();
231             return false;
232         }
233
234         signal_info *si = siginfo_next;
235         siginfo_next = si->next;
236
237         si->si.si_signo = signo;
238         si->si.si_code = code;
239         si->si.si_value = sev->sigev_value;
240
241         if( ss->pending == NULL )
242         {
243             si->next = si;
244         }
245         else
246         {
247             si->next = ss->pending->next;
248             ss->pending->next = si;
249         }
250             
251         ss->pending = si;
252     }
253     // else A non-queuable signal, just set it pending
254
255     if( thread != NULL )
256     {
257         sigaddset( &thread->sigpending, signo );
258         // just wake the thread up now if it's blocked somewhere
259         if ((thread->sigpending & ~thread->sigmask) != 0)
260         {
261             thread->thread->set_asr_pending();
262             thread->thread->release();
263         }
264     }
265     else
266     {
267         sigaddset( &sig_pending, signo );
268         // Wake up any threads in sigsuspend() and sigwait().
269         if (!signal_sigwait.get_queue()->empty())
270         {
271             signal_sigwait.broadcast();
272         } 
273         else
274         {
275             cyg_posix_pthread_release_thread( &sig_pending );
276         }
277     }
278
279     if( !locked ) signal_mutex.unlock();
280     
281     return true;
282 }
283
284 // -------------------------------------------------------------------------
285 // Deliver any pending unblocked signals to the current thread
286 // Returns true if a signal handler was called.
287
288 cyg_bool cyg_deliver_signals()
289 {
290     cyg_bool res = false;
291     
292     pthread_info *self = pthread_self_info();
293
294     // If there is no pthread_info pointer for this thread then
295     // it is not a POSIX thread and cannot have signals delivered
296     // to it.
297     
298     if( self == NULL ) return false;
299     
300     // If there are no pending signals our work is done
301     if( sig_pending == 0 && self->sigpending == 0 )
302         return false;
303
304     // If there are no unmasked pending signals our
305     // work is also done
306     if( ((sig_pending | self->sigpending) & ~self->sigmask) == 0 )
307         return false;
308
309     // As with cyg_sigqueue(), this function can get called from an
310     // ASR where the signal_mutex is already locked. Check here to
311     // avoid relocking...
312     
313     cyg_bool locked = signal_mutex.get_owner() == self->thread;
314     
315     if( !locked ) signal_mutex.lock();
316         
317     sigset_t todo;
318
319     // Since a signal handler may raise another signal, or unmask an existing
320     // signal, we loop here while there are no more unblocked signals pending.
321     while( (todo = ((sig_pending | self->sigpending) & ~self->sigmask)) != 0 )
322     {
323         // Here todo is a mask of the signals available for delivery
324         
325         int signo = 0;
326
327         // This prioritizes low numbered signals
328         HAL_LSBIT_INDEX( signo, todo );
329
330         signal_state *ss = &sigstate[signo];
331         sigset_t sigbit = 1L<<signo;
332
333         if( ss->sa.sa_handler != SIG_IGN )
334         {
335             sigset_t oldmask = self->sigmask;
336             siginfo_t lsi;
337
338             if(ss->pending != NULL)
339             {
340                 // There is a queued signal. Dequeue it and copy the
341                 // siginfo object to a local copy.
342                 
343                 signal_info *si = ss->pending->next;
344                     
345                 // Make a local copy of the siginfo object
346                 lsi = si->si;
347                     
348                 // Remove the head signal_info object from the
349                 // circular list. 
350                 if( ss->pending == si )
351                     ss->pending = NULL;
352                 else
353                     ss->pending->next = si->next;
354
355                 // Return it to the free list
356                 si->next = siginfo_next;
357                 siginfo_next = si;
358             }
359             else
360             {
361                 // There are no signals queued. Set up the local siginfo_t
362                 // object with default values. 
363
364                 lsi.si_signo = signo;
365                 lsi.si_code = SI_USER;
366                 lsi.si_value.sival_int = 0;
367             }
368             
369             // Clear the bit from the pending masks. If the pending
370             // queue is not empty, leave the bits set, otherwise clear
371             // them. Do this now so that if the signal handler longjumps
372             // out, the signal subsystem is clean.
373         
374             if( ss->pending == NULL )
375             {
376                 // Clear the bit in both masks regardless of which
377                 // one it actually came from. This is cheaper than
378                 // trying to find out.
379                 sig_pending &= ~sigbit;
380                 self->sigpending &= ~sigbit;
381             }
382
383             // Add the mask set and the signal itself to the
384             // mask while we call the signal handler
385             self->sigmask = oldmask | ss->sa.sa_mask | sigbit;
386             
387             // Unlock now so that a longjmp out of the handler
388             // does the right thing. We do this even if we did not
389             // lock the mutex since it will only recently have been
390             // relocked and thus all data is still consistent.
391                 
392             signal_mutex.unlock();
393             
394             if( ss->sa.sa_flags & SA_SIGINFO )
395             {
396                 // A sigaction delivery
397                 CYG_CHECK_FUNC_PTR( ss->sa.sa_sigaction,
398                                     "Bad sa_sigaction signal handler" );
399                 ss->sa.sa_sigaction( signo, &lsi, NULL );
400             }
401             else if ( ss->sa.sa_handler == SIG_DFL )
402             {
403                 CYG_TRACE2( true,
404                             "Unhandled POSIX signal: sig=%d, mask=%08x",
405                             signo, oldmask );
406
407                 // FIXME: should do something better here
408 #if CYGINT_ISO_EXIT
409                 _exit( -signo );
410 #endif
411                 CYG_FAIL("Unhandled POSIX signal");
412             }            
413             else
414             {
415                 // This is a standard signal delivery.
416                 CYG_CHECK_FUNC_PTR( ss->sa.sa_handler,
417                                     "Bad sa_handler signal handler" );
418
419                 ss->sa.sa_handler( signo );
420             }
421
422             // Relock the mutex 
423             signal_mutex.lock();                
424
425             // Restore original signal mask
426             self->sigmask = oldmask;
427
428             // return that we have handled a signal
429             res = true;
430         }
431     }
432
433     if( !locked ) signal_mutex.unlock();
434     
435     return res;
436 }
437
438 // -------------------------------------------------------------------------
439 // Utility routine to signal any threads waiting in sigwait*().
440
441 void cyg_posix_signal_sigwait()
442 {
443     signal_sigwait.broadcast();
444 }       
445
446 // -------------------------------------------------------------------------
447 // Action routine called from kernel alarm to deliver the SIGALRM signal.
448 // We cannot call any signal delivery functions directly here, so we simply
449 // set a flag and schedule an ASR to be called.
450
451 static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data )
452 {
453     sigset_t mask;
454     sigalrm_armed = false;
455     sigalrm_pending = true;
456     sigemptyset( &mask );
457     sigaddset( &mask, SIGALRM );
458     // Wake up any threads in sigsuspend() and sigwait() in case they
459     // are waiting for an alarm, and would have SIGALRM masked
460     signal_sigwait.broadcast();
461     
462     cyg_posix_pthread_release_thread( &mask );
463 }
464
465 // -------------------------------------------------------------------------
466 // Check for SIGALRMs. This is called from the ASR and sigtimedwait()
467 // as alarms need to be handled as a special case.
468
469 static __inline__ void check_sigalarm(void)
470 {
471     // If there is a pending SIGALRM, generate it
472     if( sigalrm_pending )
473     {
474         sigalrm_pending = false;
475         
476         struct sigevent sev;
477
478         sev.sigev_notify           = SIGEV_SIGNAL;
479         sev.sigev_signo            = SIGALRM;
480         sev.sigev_value.sival_int  = 0;
481
482         // generate the signal
483         cyg_sigqueue( &sev, SI_USER );
484     }
485 }
486
487 // -------------------------------------------------------------------------
488 // signal ASR function. This is called from the general POSIX ASR to
489 // deal with any signal related issues.
490
491 externC void cyg_posix_signal_asr(pthread_info *self)
492 {
493     check_sigalarm();
494
495     // Now call cyg_deliver_signals() to see if we can
496     // handle any signals now.
497     
498     cyg_deliver_signals();
499 }
500
501 //==========================================================================
502 // Per-thread initialization and destruction
503
504 externC void cyg_posix_thread_siginit( pthread_info *thread,
505                                        pthread_info *parentthread )
506 {
507     // Clear out signal masks
508     sigemptyset( &thread->sigpending );
509     // but threads inherit signal masks
510     if ( NULL == parentthread )
511         sigemptyset( &thread->sigmask );
512     else
513         thread->sigmask = parentthread->sigmask;
514     
515     cyg_pthread_exception_init( thread );
516 }
517
518 externC void cyg_posix_thread_sigdestroy( pthread_info *thread )
519 {
520     cyg_pthread_exception_destroy( thread );
521 }
522
523 //==========================================================================
524 // Functions to generate signals
525
526 // -------------------------------------------------------------------------
527 // Deliver sig to a process.
528 // eCos only supports the value 0 for pid.
529
530 externC int kill (pid_t pid, int sig)
531 {
532     SIGNAL_ENTRY();
533
534     if( !SIGNAL_VALID(sig) )
535         SIGNAL_RETURN(EINVAL);
536     
537     if( pid != 0 )
538         SIGNAL_RETURN(ESRCH);
539
540     struct sigevent sev;
541
542     sev.sigev_notify           = SIGEV_SIGNAL;
543     sev.sigev_signo            = sig;
544     sev.sigev_value.sival_int  = 0;
545     
546     cyg_sigqueue( &sev, SI_USER );
547
548     cyg_deliver_signals();
549     
550     SIGNAL_RETURN(0);
551 }
552
553 // -------------------------------------------------------------------------
554
555 externC int pthread_kill (pthread_t threadid, int sig)
556 {
557     SIGNAL_ENTRY();
558
559     if( !SIGNAL_VALID(sig) )
560         SIGNAL_RETURN(EINVAL);
561     
562     struct sigevent sev;
563
564     pthread_info *thread = pthread_info_id(threadid);
565
566     if( thread == NULL )
567         SIGNAL_RETURN(ESRCH);
568     
569     sev.sigev_notify           = SIGEV_SIGNAL;
570     sev.sigev_signo            = sig;
571     sev.sigev_value.sival_int  = 0;
572     
573     cyg_sigqueue( &sev, SI_USER, thread );
574
575     cyg_deliver_signals();
576     
577     SIGNAL_RETURN(0);
578 }
579
580 //==========================================================================
581 // Functions to catch signals
582
583 // -------------------------------------------------------------------------
584 // Install signal handler for sig.
585
586 externC int sigaction  (int sig, const struct sigaction *act,
587                         struct sigaction *oact)
588 {
589     SIGNAL_ENTRY();
590
591     if( !SIGNAL_VALID(sig) )
592         SIGNAL_RETURN(EINVAL);
593     
594     signal_state *ss = &sigstate[sig];
595     
596     signal_mutex.lock();
597
598     if( oact != NULL )
599         *oact = ss->sa;
600
601     ss->sa = *act;
602
603     if( ss->sa.sa_handler == SIG_IGN )
604     {
605         // Setting the handler to SIG_IGN causes any pending
606         // signals to be discarded and any queued values to also
607         // be removed.
608
609         pthread_info *self = pthread_self_info();
610         sigset_t sigbit = 1<<sig;
611
612         if( (sig_pending | self->sigpending) & sigbit )
613         {
614             // This signal is pending, clear it
615
616             sig_pending &= ~sigbit;
617             self->sigpending &= ~sigbit;
618
619             // Clean out any queued signal_info objects
620             while( ss->pending != NULL )
621             {
622                 signal_info *si = ss->pending->next;
623                 
624                 // Remove the head signal_info object from the
625                 // circular list. 
626                 if( ss->pending == si )
627                     ss->pending = NULL;
628                 else
629                     ss->pending->next = si->next;
630
631                 // Return it to the free list
632                 si->next = siginfo_next;
633                 siginfo_next = si;
634             }
635         }
636     }
637     
638     cyg_deliver_signals();
639     
640     signal_mutex.unlock();
641     
642     SIGNAL_RETURN(0);
643 }
644     
645
646 // -------------------------------------------------------------------------
647 // Queue signal to process with value.
648
649 externC int sigqueue (pid_t pid, int sig, const union sigval value)
650 {
651     SIGNAL_ENTRY();
652
653     if( !SIGNAL_VALID(sig) )
654         SIGNAL_RETURN(EINVAL);
655     
656     struct sigevent sev;
657
658     sev.sigev_notify   = SIGEV_SIGNAL;
659     sev.sigev_signo    = sig;
660     sev.sigev_value    = value;
661     
662     cyg_sigqueue( &sev, SI_QUEUE );
663
664     cyg_deliver_signals();
665     
666     SIGNAL_RETURN(0);
667 }
668     
669 //==========================================================================
670 // Functions to deal with current blocked and pending masks
671
672 // -------------------------------------------------------------------------
673 // Set process blocked signal mask
674 // Map this onto pthread_sigmask().
675
676 externC int sigprocmask  (int how, const sigset_t *set, sigset_t *oset)
677 {
678     return pthread_sigmask( how, set, oset);
679 }
680     
681
682 // -------------------------------------------------------------------------
683 // Set calling thread's blocked signal mask
684
685 externC int pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
686 {
687     int err = 0;
688     
689     SIGNAL_ENTRY();
690
691     pthread_info *self = pthread_self_info();
692     // Save old set
693     if( oset != NULL )
694         *oset = self->sigmask;
695
696     if( set != NULL )
697     {
698         switch( how )
699         {
700         case SIG_BLOCK:
701             self->sigmask |= *set;
702             break;
703         
704         case SIG_UNBLOCK:
705             self->sigmask &= ~*set;
706             break;
707             
708         case SIG_SETMASK:
709             self->sigmask = *set;
710             break;
711
712         default:
713             err = EINVAL;
714             break;
715         }
716     }
717
718     // Deliver any newly unblocked signals
719     cyg_deliver_signals();
720     
721     SIGNAL_RETURN(err);
722 }
723
724 // -------------------------------------------------------------------------
725 // Exported routine to set calling thread's blocked signal mask
726 //
727 // Optionally set and return the current thread's signal mask. This is
728 // exported to other packages so that they can manipulate the signal
729 // mask without necessarily having them delivered (as calling
730 // pthread_sigmask() would). Signals can be delivered by calling
731 // cyg_posix_deliver_signals().
732
733 externC void cyg_pthread_sigmask_set (const sigset_t *set, sigset_t *oset)
734 {
735     pthread_info *self = pthread_self_info();
736
737     if( self != NULL )
738     {
739         if( oset != NULL )
740             *oset = self->sigmask;
741
742         if( set != NULL )
743             self->sigmask = *set;
744     }
745 }
746
747 // -------------------------------------------------------------------------
748 // Exported routine to test for any pending signals.
749 //
750 // This routine tests for any pending undelivered, unmasked
751 // signals. If there are any it returns true.  This is exported to
752 // other packages, such as FILEIO, so that they can detect whether to
753 // abort a current API call with an EINTR result.
754
755 externC cyg_bool cyg_posix_sigpending(void)
756 {
757     pthread_info *self = pthread_self_info();
758
759     if( self == NULL )
760         return false;
761     
762     return ( ((sig_pending | self->sigpending) & ~self->sigmask) != 0 );
763 }
764
765 // -------------------------------------------------------------------------
766 // Exported routine to deliver selected signals
767 //
768 // This routine optionally sets the given mask and then tries to
769 // deliver any pending signals that have been unmasked. This is
770 // exported to other packages so that they can cause signals to be
771 // delivered at controlled points during execution.
772
773 externC void cyg_posix_deliver_signals( const sigset_t *mask )
774 {
775     sigset_t oldmask;
776     pthread_info *self = pthread_self_info();
777
778     if( self != NULL )
779     {
780         if( mask != NULL )
781         {
782             oldmask = self->sigmask;
783             self->sigmask = *mask;
784         }
785         else
786             oldmask = 0;   // silence warning
787
788         cyg_deliver_signals();
789
790         if( mask != NULL )        
791             self->sigmask = oldmask;
792     }
793 }
794
795 // -------------------------------------------------------------------------
796 // Get set of pending signals for this process
797
798 externC int sigpending  (sigset_t *set)
799 {
800     SIGNAL_ENTRY();
801
802     if( set == NULL )
803         SIGNAL_RETURN(EINVAL);
804     
805     pthread_info *self = pthread_self_info();
806     
807     *set = self->sigpending | sig_pending;
808     
809     SIGNAL_RETURN(0);
810 }
811     
812
813 //==========================================================================
814 // Wait for or accept signals
815
816 // -------------------------------------------------------------------------
817 // Block signals in set and wait for a signal
818
819 externC int sigsuspend  (const sigset_t *set)
820 {
821     SIGNAL_ENTRY();
822
823     pthread_info *self = pthread_self_info();
824
825     signal_mutex.lock();
826
827     // Save the old mask and set the current mask to
828     // the one supplied.
829     sigset_t old = self->sigmask;
830     self->sigmask = *set;
831
832     // Loop until a signal gets delivered
833     while( !cyg_deliver_signals() )
834         signal_sigwait.wait();
835
836     self->sigmask = old;
837     
838     signal_mutex.unlock();
839     
840     SIGNAL_RETURN(EINTR);
841 }
842     
843
844 // -------------------------------------------------------------------------
845 // Wait for a signal in set to arrive
846 // Implement this as a variant on sigtimedwait().
847
848 externC int sigwait  (const sigset_t *set, int *sig)
849 {
850     SIGNAL_ENTRY();
851
852     siginfo_t info;
853     
854     int ret = sigtimedwait( set, &info, NULL );
855
856     if( ret == -1 )
857         SIGNAL_RETURN(errno);
858
859     *sig = ret;
860     
861     SIGNAL_RETURN(0);
862 }
863
864 // -------------------------------------------------------------------------
865 // Do the same as sigwait() except return a siginfo_t object too.
866 // Implement this as a variant on sigtimedwait().
867
868 externC int sigwaitinfo  (const sigset_t *set, siginfo_t *info)
869 {
870     SIGNAL_ENTRY();
871
872     int ret = sigtimedwait( set, info, NULL );
873     
874     SIGNAL_RETURN_VALUE(ret);
875 }
876
877 // -------------------------------------------------------------------------
878 // Wait either for a signal in the given set to become pending, or
879 // for the timeout to expire. If timeout is NULL, wait for ever.
880
881 externC int sigtimedwait  (const sigset_t *set, siginfo_t *info,
882                            const struct timespec *timeout)
883 {
884     SIGNAL_ENTRY();
885
886     // check for cancellation first.
887     pthread_testcancel();
888
889     int err = 0;
890     cyg_tick_count ticks;
891
892     if( timeout == NULL ) ticks = 0;
893     else ticks = cyg_timespec_to_ticks( timeout ) +
894              Cyg_Clock::real_time_clock->current_value();
895
896     pthread_info *self = pthread_self_info();
897     
898     signal_mutex.lock();
899
900     sigset_t todo;
901
902     // Wait for a signal in the set to become pending
903     while( (todo = (*set & (sig_pending | self->sigpending))) == 0 )
904     {
905         // If timeout is not NULL, do a timed wait on the
906         // sigwait condition variable. If it is NULL - wait
907         // until we are woken.
908         if( timeout )
909         {
910             if( ticks == 0 || !signal_sigwait.wait(ticks) )
911             {
912                 // If the timeout is actually zero, or we have waited and
913                 // timed out, then we must quit with an error.
914                 err = EAGAIN;
915                 break;
916             }
917         }
918         else {
919             if ( !signal_sigwait.wait() ) {
920                 // check we weren't woken up forcibly (e.g. to be cancelled)
921                 // if so, pretend it's an error
922                 err = EAGAIN;
923                 break;
924             }
925         }
926         
927         // Special case check for SIGALRM since the fact SIGALRM is masked
928         // would have prevented it being set pending in the alarm handler.
929         check_sigalarm();
930
931         cyg_posix_timer_asr(self);
932     }
933
934     if( err == 0 )
935     {
936         // There is a signal in the set that is pending: deliver
937         // it. todo contains a mask of all the signals that could be
938         // delivered now, but we only want to deliver one of them.
939
940         int signo = 0;
941
942         // Select the lowest numbered signal from the todo mask
943         HAL_LSBIT_INDEX( signo, todo );
944
945         signal_state *ss = &sigstate[signo];
946         sigset_t sigbit = 1L<<signo;
947
948         if( (ss->sa.sa_flags & SA_SIGINFO) && (ss->pending != NULL) )
949         {
950             // If the SA_SIGINFO bit is set, then there
951             // will be a signal_info object queued on the
952             // pending field.
953
954             signal_info *si = ss->pending->next;
955             *info = si->si;
956
957             // Remove the head signal_info object from the
958             // circular list. 
959             if( ss->pending == si )
960                 ss->pending = NULL;
961             else
962                 ss->pending->next = si->next;
963                 
964             si->next = siginfo_next;
965             siginfo_next = si;
966                 
967         }
968         else
969         {
970             // Not a queued signal, or there is no signal_info object
971             // on the pending queue: fill in info structure with
972             // default values.
973             info->si_signo           = signo;
974             info->si_code            = SI_USER;
975             info->si_value.sival_int = 0;
976         }
977
978         // Clear the bit from the pending masks. If the pending
979         // queue is not empty, leave the bits set, otherwise clear
980         // them.
981         
982         if( ss->pending == NULL )
983         {
984             // Clear the bit in both masks regardless of which
985             // one it actually came from. This is cheaper than
986             // trying to find out.
987             sig_pending &= ~sigbit;
988             self->sigpending &= ~sigbit;
989         }
990
991         // all done
992     }
993     
994     signal_mutex.unlock();
995
996     pthread_testcancel();
997
998     if (err)
999         SIGNAL_RETURN(err);
1000     else
1001         SIGNAL_RETURN_VALUE( info->si_signo );
1002 }
1003
1004 //==========================================================================
1005 // alarm, pause and sleep
1006
1007 // -------------------------------------------------------------------------
1008 // Generate SIGALRM after some number of seconds
1009
1010 externC unsigned int alarm( unsigned int seconds )
1011 {
1012     int res = 0;
1013     struct timespec tv;
1014     cyg_tick_count trigger, interval;
1015
1016     SIGNAL_ENTRY();
1017
1018     signal_mutex.lock();
1019
1020     if( sigalrm_armed )
1021     {
1022         sigalrm_alarm.disable();
1023
1024         sigalrm_alarm.get_times( &trigger, &interval );
1025
1026         // Convert trigger time back to interval
1027         trigger -= Cyg_Clock::real_time_clock->current_value();
1028         
1029         cyg_ticks_to_timespec( trigger, &tv );
1030
1031         res = tv.tv_sec;
1032         
1033         sigalrm_armed = false;
1034     }
1035
1036     if( seconds != 0 )
1037     {
1038         // Here we know that the sigalrm_alarm is unarmed, set it up
1039         // to trigger in the required number of seconds.
1040
1041         tv.tv_sec = seconds;
1042         tv.tv_nsec = 0;
1043
1044         trigger = cyg_timespec_to_ticks( &tv );
1045
1046         // Convert trigger interval to absolute time
1047         trigger += Cyg_Clock::real_time_clock->current_value();
1048         
1049         sigalrm_alarm.initialize( trigger, 0 );
1050
1051         sigalrm_armed = true;
1052     }
1053     
1054     signal_mutex.unlock();
1055
1056     CYG_REPORT_RETVAL(res);
1057     
1058     return res;
1059 }
1060
1061 // -------------------------------------------------------------------------
1062 // Wait for a signal to be delivered.
1063
1064 externC int pause( void )
1065 {
1066     SIGNAL_ENTRY();
1067
1068     signal_mutex.lock();
1069
1070     // Check for any pending signals that can be delivered and
1071     // if there are none, wait for a signal to be generated
1072     while( !cyg_deliver_signals() )
1073         signal_sigwait.wait();
1074
1075     signal_mutex.unlock();
1076     
1077     SIGNAL_RETURN(EINTR);
1078 }
1079
1080 //==========================================================================
1081 // Signal sets
1082
1083 // -------------------------------------------------------------------------
1084 // Clear all signals from set.
1085
1086 externC int sigemptyset  (sigset_t *set)
1087 {
1088     SIGNAL_ENTRY();
1089
1090     *set = 0;
1091     
1092     SIGNAL_RETURN(0);
1093 }
1094     
1095
1096 // -------------------------------------------------------------------------
1097 // Set all signals in set.
1098
1099 externC int sigfillset  (sigset_t *set)
1100 {
1101     SIGNAL_ENTRY();
1102
1103     *set = ~0;
1104     
1105     SIGNAL_RETURN(0);
1106 }
1107     
1108
1109 // -------------------------------------------------------------------------
1110 // Add signo to set.
1111
1112 externC int sigaddset  (sigset_t *set, int signo)
1113 {
1114     SIGNAL_ENTRY();
1115
1116     int err = 0;
1117     
1118     if( !SIGNAL_VALID(signo) )
1119         err = EINVAL;
1120     else *set |= 1<<signo;
1121     
1122     SIGNAL_RETURN(err);
1123 }
1124     
1125
1126 // -------------------------------------------------------------------------
1127 // Remove signo from set.
1128
1129 externC int sigdelset  (sigset_t *set, int signo)
1130 {
1131     SIGNAL_ENTRY();
1132
1133     int err = 0;
1134     
1135     if( !SIGNAL_VALID(signo) )
1136         err = EINVAL;
1137     else *set &= ~(1<<signo);
1138     
1139     SIGNAL_RETURN(err);
1140 }
1141     
1142
1143 // -------------------------------------------------------------------------
1144 // Test whether signo is in set
1145
1146 externC int sigismember  (const sigset_t *set, int signo)
1147 {
1148     SIGNAL_ENTRY();
1149
1150     int ret = 0;
1151     
1152     if( !SIGNAL_VALID(signo) )
1153         SIGNAL_RETURN(EINVAL);
1154
1155     if( *set & (1<<signo) ) ret = 1;
1156
1157     CYG_REPORT_RETVAL( ret );
1158     return ret;
1159 }
1160
1161 //==========================================================================
1162 // ISO C compatibility functions
1163
1164 // -------------------------------------------------------------------------
1165 // Installs a new signal handler for the specified signal, and returns
1166 // the old handler
1167
1168 externC sa_sighandler_t signal(int sig, sa_sighandler_t handler)
1169 {
1170     SIGNAL_ENTRY();
1171
1172     int err;
1173     sa_sighandler_t ret;
1174     struct sigaction new_action;
1175     struct sigaction old_action;
1176
1177     sigemptyset( &new_action.sa_mask );
1178     new_action.sa_flags = 0;
1179     new_action.sa_handler = handler;
1180
1181     err = sigaction( sig, &new_action, &old_action );
1182
1183     if( err < 0 )
1184         ret = SIG_ERR;
1185     else ret = old_action.sa_handler;
1186     
1187     CYG_REPORT_RETVAL( ret );
1188     return ret;    
1189 }
1190
1191 // -------------------------------------------------------------------------
1192 // raise() - ISO C 7.7.2 //
1193 //
1194 // Raises the signal, which will cause the current signal handler for
1195 // that signal to be called
1196
1197 externC int raise(int sig)
1198 {
1199     return kill( 0, sig );
1200 }
1201
1202 // -------------------------------------------------------------------------
1203 // siglongjmp()
1204 // Restores signal mask and longjumps.
1205
1206 __externC void siglongjmp( sigjmp_buf env, int val )
1207 {
1208     CYG_REPORT_FUNCNAME( "siglongjmp" );
1209     CYG_REPORT_FUNCARG2( "&env=%08x, val=%d", &env, val );
1210
1211     // ISO C says that if we are passed val == 0, then we change it to 1
1212     if( val == 0 )
1213         val = 1;
1214
1215     if( env[0].__savemask )
1216         pthread_sigmask( SIG_SETMASK, &env[0].__sigsavemask, NULL );
1217     
1218     HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering
1219     hal_longjmp( env[0].__jmp_buf, val );
1220     HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering
1221
1222 #ifdef CYGDBG_USE_ASSERTS
1223     CYG_ASSERT( 0, "siglongjmp should not have reached this point!" );
1224 #else
1225     for (;;)
1226         CYG_EMPTY_STATEMENT;
1227 #endif
1228     
1229 }
1230
1231 #endif // ifdef CYGPKG_POSIX_SIGNALS
1232
1233 // -------------------------------------------------------------------------
1234 // EOF signal.cxx