⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      signal.cxx
//
//      POSIX signal functions implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):           nickg
// Contributors:        nickg
// Date:                2000-03-27
// Purpose:             POSIX signal functions implementation
// Description:         This file contains the implementation of the POSIX signal
//                      functions.
//              
//              
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/posix.h>

#ifdef CYGPKG_POSIX_SIGNALS

#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/isoinfra.h>

#include <cyg/kernel/ktypes.h>          // base kernel types
#include <cyg/infra/cyg_trac.h>         // tracing macros
#include <cyg/infra/cyg_ass.h>          // assertion macros

#include "pprivate.h"                   // POSIX private header

#include <signal.h>                     // our header
#include <setjmp.h>
#include <unistd.h>                     // _exit

#include <cyg/kernel/clock.hxx>
#include <cyg/kernel/thread.hxx>
#include <cyg/kernel/clock.inl>
#include <cyg/kernel/thread.inl>

// -------------------------------------------------------------------------
// Internal definitions

// Handle entry to a signal package function. 
#define SIGNAL_ENTRY() CYG_REPORT_FUNCTYPE( "returning %d" );

// Do a signal package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define SIGNAL_RETURN(err)                      \CYG_MACRO_START                                 \    int __retval = 0;                           \    if( err != 0 ) __retval = -1, errno = err;  \    CYG_REPORT_RETVAL( __retval );              \    return __retval;                            \CYG_MACRO_END

// Similarly for functions that have valid non-zero returns
#define SIGNAL_RETURN_VALUE(val)                \CYG_MACRO_START                                 \    CYG_REPORT_RETVAL( val );                   \    return val;                                 \CYG_MACRO_END

// Range check on a signal value.
#define SIGNAL_VALID(_sig_) (((_sig_) > 0) && ((_sig_) < ((int)sizeof(sigset_t)*8)))

//==========================================================================
// Signal management structures

typedef struct signal_info
{
    struct signal_info          *next;  // link in list of pending signals
    siginfo_t                   si;     // siginfo to pass to handler
} signal_info;

typedef struct
{
    struct sigaction            sa;     // Sigaction defining what to do
    signal_info                 *pending; // List of pending signals - this is
                                          // a circular list with pending pointing
                                          // to the tail element (or NULL if empty).
} signal_state;

//==========================================================================
// Signal management variables

// Lock used to protect signal management structures
Cyg_Mutex signal_mutex CYGBLD_POSIX_INIT;

// Condition variable for all threads in sigsuspend() and sigwait()
// to wait on.
Cyg_Condition_Variable signal_sigwait( signal_mutex ) CYGBLD_POSIX_INIT;

// Global pending signal set
sigset_t sig_pending;

// Array controlling signal states
static signal_state sigstate[sizeof(sigset_t)*8];

// Array of available signal_info objects for queueing signals
static signal_info siginfo[SIGQUEUE_MAX];

// List of free signal_info objects
static signal_info *siginfo_next = NULL;

//==========================================================================
// Variables used to support alarm()

// Forward def of action function
static void sigalrm_action( Cyg_Alarm *alarm, CYG_ADDRWORD data );

// Kernel alarm object
static Cyg_Alarm sigalrm_alarm( Cyg_Clock::real_time_clock, sigalrm_action, 0 ) CYGBLD_POSIX_INIT;

// Set true when alarm is armed
volatile cyg_bool sigalrm_armed = false;

// Set true when alarm has fired and is waiting to be delivered
volatile cyg_bool sigalrm_pending = false;

//==========================================================================
// Implementation functions.
// These are where the real work of the signal mechanism gets done.

externC void cyg_posix_signal_start()
{
    // Chain all free signal_info objects together
    for( int i = 0; i < SIGQUEUE_MAX; i++ )
    {
        siginfo[i].next = siginfo_next;
        siginfo_next = &siginfo[i];
    }
    
    // initialize all signal actions to SIG_DFL
    for ( unsigned int i=0; i<(sizeof(sigstate)/sizeof(signal_state)); i++ )
    {
        sigstate[i].sa.sa_handler = SIG_DFL;
    }

    // Clear the pending signal set
    sigemptyset( &sig_pending );
}

// -------------------------------------------------------------------------
// Generate a signal

cyg_bool cyg_sigqueue( const struct sigevent *sev, int code,
                       pthread_info *thread )
{
    if( sev->sigev_notify == SIGEV_NONE )
    {
        // Do nothing
        return true;
    }

    if( sev->sigev_notify == SIGEV_THREAD )
    {
        // create a thread to run the notification
        // function.
        // FIXME: implement SIGEV_THREAD
        return true;
    }

    // Otherwise we must have a SIGEV_SIGNAL notification

    // Find out whether the current thread already has the mutex
    // locked. This is a distinct possibility if this function is
    // called from the ASR while exiting the signal_sigwait condvar in
    // pause() and sigtimedwait().
    
    pthread_info *self = pthread_self_info();
    cyg_bool locked = (self != NULL) && (signal_mutex.get_owner() == self->thread);
    
    // Lock the mutex only if we do not already own it
    if( !locked ) signal_mutex.lock();
    
    int signo = sev->sigev_signo;
    signal_state *ss = &sigstate[signo];

    if( ss->sa.sa_flags & SA_SIGINFO )
    {
        // We have a queuable signal, allocate a signal_info
        // object and add it to the queue.

        if( siginfo_next == NULL )
        {
            if( !locked ) signal_mutex.unlock();
            return false;
        }

        signal_info *si = siginfo_next;
        siginfo_next = si->next;

        si->si.si_signo = signo;
        si->si.si_code = code;
        si->si.si_value = sev->sigev_value;

        if( ss->pending == NULL )
        {
            si->next = si;
        }
        else
        {
            si->next = ss->pending->next;
            ss->pending->next = si;
        }
            
        ss->pending = si;
    }
    // else A non-queuable signal, just set it pending

    if( thread != NULL )
    {
        sigaddset( &thread->sigpending, signo );
        // just wake the thread up now if it's blocked somewhere
        if ((thread->sigpending & ~thread->sigmask) != 0)
        {
            thread->thread->set_asr_pending();
            thread->thread->release();
        }
    }
    else
    {
        sigaddset( &sig_pending, signo );
        // Wake up any threads in sigsuspend() and sigwait().
        if (!signal_sigwait.get_queue()->empty())
        {
            signal_sigwait.broadcast();
        } 
        else
        {
            cyg_posix_pthread_release_thread( &sig_pending );
        }
    }

    if( !locked ) signal_mutex.unlock();
    
    return true;
}

// -------------------------------------------------------------------------
// Deliver any pending unblocked signals to the current thread
// Returns true if a signal handler was called.

cyg_bool cyg_deliver_signals()
{
    cyg_bool res = false;
    
    pthread_info *self = pthread_self_info();

    // If there is no pthread_info pointer for this thread then
    // it is not a POSIX thread and cannot have signals delivered
    // to it.
    
    if( self == NULL ) return false;
    
    // If there are no pending signals our work is done
    if( sig_pending == 0 && self->sigpending == 0 )
        return false;

    // If there are no unmasked pending signals our
    // work is also done
    if( ((sig_pending | self->sigpending) & ~self->sigmask) == 0 )
        return false;

    // As with cyg_sigqueue(), this function can get called from an
    // ASR where the signal_mutex is already locked. Check here to
    // avoid relocking...
    
    cyg_bool locked = signal_mutex.get_owner() == self->thread;
    
    if( !locked ) signal_mutex.lock();
        
    sigset_t todo;

    // Since a signal handler may raise another signal, or unmask an existing
    // signal, we loop here while there are no more unblocked signals pending.
    while( (todo = ((sig_pending | self->sigpending) & ~self->sigmask)) != 0 )
    {
        // Here todo is a mask of the signals available for delivery
        
        int signo = 0;

        // This prioritizes low numbered signals
        HAL_LSBIT_INDEX( signo, todo );

        signal_state *ss = &sigstate[signo];
        sigset_t sigbit = 1L<<signo;

        if( ss->sa.sa_handler != SIG_IGN )
        {
            sigset_t oldmask = self->sigmask;
            siginfo_t lsi;

            if(ss->pending != NULL)
            {
                // There is a queued signal. Dequeue it and copy the
                // siginfo object to a local copy.
                
                signal_info *si = ss->pending->next;
                    
                // Make a local copy of the siginfo object
                lsi = si->si;
                    
                // Remove the head signal_info object from the
                // circular list. 
                if( ss->pending == si )
                    ss->pending = NULL;
                else
                    ss->pending->next = si->next;

                // Return it to the free list
                si->next = siginfo_next;
                siginfo_next = si;
            }
            else
            {
                // There are no signals queued. Set up the local siginfo_t
                // object with default values. 

                lsi.si_signo = signo;
                lsi.si_code = SI_USER;
                lsi.si_value.sival_int = 0;
            }
            
            // Clear the bit from the pending masks. If the pending
            // queue is not empty, leave the bits set, otherwise clear
            // them. Do this now so that if the signal handler longjumps
            // out, the signal subsystem is clean.
        
            if( ss->pending == NULL )
            {
                // Clear the bit in both masks regardless of which
                // one it actually came from. This is cheaper than
                // trying to find out.
                sig_pending &= ~sigbit;
                self->sigpending &= ~sigbit;
            }

            // Add the mask set and the signal itself to the
            // mask while we call the signal handler
            self->sigmask = oldmask | ss->sa.sa_mask | sigbit;
            
            // Unlock now so that a longjmp out of the handler
            // does the right thing. We do this even if we did not
            // lock the mutex since it will only recently have been
            // relocked and thus all data is still consistent.
                
            signal_mutex.unlock();
            
            if( ss->sa.sa_flags & SA_SIGINFO )
            {
                // A sigaction delivery
                CYG_CHECK_FUNC_PTR( ss->sa.sa_sigaction,
                                    "Bad sa_sigaction signal handler" );
                ss->sa.sa_sigaction( signo, &lsi, NULL );
            }
            else if ( ss->sa.sa_handler == SIG_DFL )
            {
                CYG_TRACE2( true,
                            "Unhandled POSIX signal: sig=%d, mask=%08x",
                            signo, oldmask );

                // FIXME: should do something better here
#if CYGINT_ISO_EXIT
                _exit( -signo );
#endif
                CYG_FAIL("Unhandled POSIX signal");
            }            
            else
            {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -