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