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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [compat/] [posix/] [v2_0/] [src/] [signal.cxx] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
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 signal_sigwait( signal_mutex ) CYGBLD_POSIX_INIT;
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 sigalrm_alarm( Cyg_Clock::real_time_clock, sigalrm_action, 0 ) CYGBLD_POSIX_INIT;
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

powered by: WebSVN 2.1.0

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