OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [compat/] [posix/] [current/] [src/] [signal.cxx] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.