Logo Search packages:      
Sourcecode: u++ version File versions

uSignal.cc

//                              -*- Mode: C++ -*- 
// 
// uC++ Version 5.0.1, Copyright (C) Peter A. Buhr 1994
// 
// uSignal.cc -- 
// 
// Author           : Peter A. Buhr
// Created On       : Sun Dec 19 16:32:13 1993
// Last Modified By : Peter A. Buhr
// Last Modified On : Thu Sep  2 12:24:09 2004
// Update Count     : 622
//
// This  library is free  software; you  can redistribute  it and/or  modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
// option) any later version.
// 
// This library 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 Lesser General Public License
// for more details.
// 
// You should  have received a  copy of the  GNU Lesser General  Public License
// along  with this library.
// 


#define __U_KERNEL__
#include <uC++.h>
//#include <uDebug.h>

#include <cstdio>
#include <cstring>
#include <cerrno>
#include <unistd.h>                             // _exit
#include <sys/wait.h>
#include <sys/types.h>


// Binding of signal numbers to meaning is not unique on UNIX systems. A
// meaningful description is generated for the most common signals.
// (Designators would allow the descriptions to be in an array.)
static const char *uSignalDescription( int sig ) {
    switch ( sig ) {
      case SIGHUP:
      return "hangup";
      case SIGINT:
      return "interrupt";
      case SIGQUIT:
      return "quit";
      case SIGILL:
      return "illegal instruction";
      case SIGTRAP:
      return "trace trap";
      case SIGABRT:
      return "iot/abort";
      case SIGFPE:
      return "floating point exception";
      case SIGKILL:
      return "kill";
      case SIGBUS:
      return "bus error";
      case SIGSEGV:
      return "segmentation violation";
      case SIGSYS:
      return "bad argument to system call";
      case SIGPIPE:
      return "write on a pipe with no one to read it";
      case SIGALRM:
      return "alarm clock";
      case SIGTERM:
      return "software termination signal";
      case SIGUSR1:
      return "user defined signal 1";
      case SIGUSR2:
      return "user defined signal 2";
      case SIGCHLD:
      return "child status change";
      default:
      return "";
    } // switch
}; // uSignalDescription


void uSigHandlerModule::uSSignal( int sig, void (*handler)(__U_SIGPARMS__), int flags ) { // name clash with uSignal statement
    struct sigaction act;
    *(void (**)(__U_SIGPARMS__))(&act.sa_sigaction) = handler; // cast because handler type is inconsistent
    sigemptyset( &act.sa_mask );
    sigaddset( &act.sa_mask, SIGALRM );               // disable SIGALRM during signal handler
    act.sa_flags = flags;

    if ( sigaction( sig, &act, NULL ) == -1 ) {
      // THE KERNEL IS NOT STARTED SO CALL NO uC++ ROUTINES!
      fprintf( stderr, " uSigHandlerModule::uSSignal( sig:%d, handler:0x%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
             sig, handler, flags, errno, strerror( errno ) );
      _exit( -1 );
    } // if
} // uSigHandlerModule::uSSignal


void *uSigHandlerModule::uSignalContextPC( __U_SIGCXT__ cxt ) {
#if defined( __i386__ )
    return (void *)(cxt->uc_mcontext.gregs[REG_EIP]);
#elif defined( __ia64__ )
    return (void *)(cxt->uc_mcontext.sc_ip);
#elif defined( __sparc__ )
    return (void *)(cxt->uc_mcontext.gregs[REG_PC]);
#elif defined( __mips__ )
    return (void *)((ucontext_t *)cxt)->uc_mcontext.gregs[CXT_EPC];
#else
    #error uC++ internal error : unsupported architecture
#endif
} // uSigHandlerModule::uSignalContextPC


void uSigHandlerModule::uSigChldHandler( __U_SIGPARMS__ ) {
    // The SIGCHLD signal is delivered as the result of a child process
    // terminating.  If the child process terminates because of some error, the
    // application is terminated.

  if ( uKernelModule::uGlobalAbort ) return;          // close down in progress, ignore signal

    pid_t pid;
    int status = 0;

    // SIGALRM is masked so no EINTR looping.
    pid = ::waitpid( -1, &status, WNOHANG );          // grab the pid of any child and its exit status
    // uProcWait and uSigChldHandler race to wait on the pid for normal
    // termination so the loser ignores the ECHILD.
    if ( pid == -1 && errno != ECHILD ) {
      uAbort( "uSigHandlerModule::uSigChldHandler : internal error, error(%d) %s.", errno, strerror( errno ) );
    } // if

#ifdef __U_DEBUG_H__
    char buffer[256];
    uDebugPrtBuf( buffer, "uSigChldHandler, pid:%ld, status:0x%x, uThisTask:%.256s (0x%p), uThisCoroutine:0x%p\n",
              (long int)pid, status, uThisTask().uGetName(), &uThisTask(), &uThisCoroutine() );
#endif // __U_DEBUG_H__

    // pid == 0 => an external signal not caused by the child processes.
    // Possibly the shell putting the application into the background.  As
    // well, the uProcWait may have already reaped the process sending the
    // sigchld but there are still running child processes.

    if ( pid > 0 && WIFSIGNALED( status ) ) {         // process died as the result of some signal ?
      // Terminate the application with an appropriate error message.

      uKernelModule::uCoreDumped = true;        // assume the child dumped core
      uAbort( ": child process %ld died with signal %d %s", (long int)pid, WTERMSIG( status ), uSignalDescription( WTERMSIG( status ) ) );
    } // if
} // uSigHandlerModule::uSigChldHandler


void uSigHandlerModule::uSigTermHandler( __U_SIGTYPE__ ) {
    // This routine handles a SIGHUP, SIGINT, or a SIGTERM signal.  The signal
    // is delivered to the root process as the result of some action on the
    // part of the user attempting to terminate the application.  It must be
    // caught here so that all processes in the application may be terminated.

#ifdef __U_DEBUG_H__
    char buffer[256];
    uDebugPrtBuf( buffer, "uSigTermHandler, cluster:%.256s (0x%p), processor:0x%p\n",
              uThisCluster().uGetName(), &uThisCluster(), &uThisProcessor() );
#endif // __U_DEBUG_H__

  if ( uKernelModule::uGlobalAbort ) return;          // close down in progress, ignore signal

    uAbort( ": application interrupted by a termination signal." );
} // uSigHandlerModule::uSigTermHandler


void uSigHandlerModule::uSigAlrmHandler( __U_SIGPARMS__ ) {
#ifdef __U_DEBUG_H__
    char buffer[256];
#endif // __U_DEBUG_H__

#if defined( __ia64__ ) && defined( __U_MULTI__ )
    // The following check must be executed first on the ia64.  It clears p7 to indicate a signal occured
    // during a THREAD_GETMEM / THREAD_SETMEM.
    if ( *(unsigned long*)cxt->uc_mcontext.sc_gr[13] & 1 ) {
      cxt->uc_mcontext.sc_pr &= ~(1 << 7);
      return;
    } // if
#endif // __ia64__ && __U_MULTI__

    // This routine handles a SIGALRM signal.  This signal is delivered as the
    // result of time slicing being enabled, a processor is being woken up
    // after being idle for some time, or some intervention being delivered to
    // a thread.  This handler attempts to yield the currently executing thread
    // so that another thread may be scheduled by this processor.

  if ( uKernelModule::uGlobalAbort ) return;          // close down in progress, ignore signal
  if ( THREAD_GETMEM( uInKernelRF ) ) {               // roll-forward flag on ? spurious alarm
      // set roll forward to 2 to detect alarms during roll forward
      THREAD_SETMEM( uInKernelRF, 2 );
      return;
  } // if

    int terrno = errno;

    if ( THREAD_GETMEM( uDisableInt ) || THREAD_GETMEM( uDisableIntSpin ) ) { // inside the kernel or spinlock acquired
#ifdef __U_DEBUG_H__
          uDebugPrtBuf( buffer, "uSigAlrmHandler1, task:0x%p, stack:0x%p, address:0x%p, uDisableInt:%d, uDisableIntCnt:%d\n",
#if defined( __solaris__ ) || defined( __irix__ )
                    &uThisTask(), uThisTask().uStackPointer(), uSignalContextPC( cxt ),
                    THREAD_GETMEM( uDisableInt ), THREAD_GETMEM( uDisableIntCnt ) );
#elif defined( __ia64__ )
                        &uThisTask(), cxt->uc_stack, uSignalContextPC( cxt ),
                      THREAD_GETMEM( uDisableInt ), THREAD_GETMEM( uDisableIntCnt ) );
#else
                    &uThisTask(), cxt->sc_sp, uSignalContextPC( cxt ),
                    THREAD_GETMEM( uDisableInt ), THREAD_GETMEM( uDisableIntCnt ) );
#endif
#endif // __U_DEBUG_H__
            int newRF = THREAD_GETMEM( uInKernelRF ) + 1;
          THREAD_SETMEM( uInKernelRF, newRF );
    } else {            // and not in kernel or spinlock ?
      if ( sigprocmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), NULL ) == -1 ) { // clear the blocked SIGALRM signal so more can arrive
          uAbort( "internal error, sigprocmask" );
      } // if

#ifdef __U_DEBUG_H__
          uDebugPrtBuf( buffer, "uSigAlrmHandler2, task:0x%p, stack:0x%p, address:0x%p, uDisableInt:%d, uDisableIntCnt:%d\n",
#if defined( __solaris__ ) || defined( __irix__ )
                    &uThisTask(), uThisTask().uStackPointer(), uSignalContextPC( cxt ),
                    THREAD_GETMEM( uDisableInt ), THREAD_GETMEM( uDisableIntCnt ) );
#elif defined( __ia64__ )
                        &uThisTask(), cxt->uc_stack, uSignalContextPC( cxt ),
                      THREAD_GETMEM( uDisableInt ), THREAD_GETMEM( uDisableIntCnt ) );
#else
                    &uThisTask(), cxt->sc_sp, uSignalContextPC( cxt ),
                    THREAD_GETMEM( uDisableInt ), THREAD_GETMEM( uDisableIntCnt ) );
#endif
#endif // __U_DEBUG_H__

#ifdef __U_DEBUG__
      // The current PC is stored, so that it can be looked up by the local
      // debugger to check if the task was time sliced at a breakpoint
      // location.

      uThisTask().DebugPCandSRR = uSignalContextPC( cxt );
#endif // __U_DEBUG__

      THREAD_GETMEM( uSelf )->uRollForward();

#ifdef __U_DEBUG__
      // Reset this field before task is started, to denote that this task is
      // not blocked.

      uThisTask().DebugPCandSRR = NULL;
#endif // __U_DEBUG__

#if 0                                     // TEMPORARY: unnecessary code ?
      sigset_t new_mask;
      sigemptyset( &new_mask );
      sigaddset( &new_mask, SIGALRM );
      if ( sigprocmask( SIG_BLOCK, &new_mask, NULL ) == -1 ) {
          uAbort( "internal error, sigprocmask" );
      } // if
#endif
    } // if

    // Block all signals from arriving.
    sigset_t new_mask, mask;
    sigfillset( &new_mask );

    if ( sigprocmask( SIG_BLOCK, &new_mask, &mask ) == -1 ) {
        uAbort( "internal error, sigprocmask" );
    } // if

#ifdef __U_MULTI__
#if defined( __i386__ )
    ((ucontext_t *)cxt)->uc_mcontext.gregs[REG_GS] = THREAD_GETMEM( ldtValue );
#elif defined( __ia64__ )
    ((ucontext_t *)cxt)->uc_mcontext.sc_gr[13] = (unsigned long)THREAD_GETMEM( threadPointer );
#elif defined( __sparc__ )
    ((ucontext_t *)cxt)->uc_mcontext.gregs[REG_G7] = (int)THREAD_GETMEM( uSelf );
#endif
#endif // __U_MULTI__

    errno = terrno;
} // uSigHandlerModule::uSigAlrmHandler


void uSigHandlerModule::uSigSegvBusHandler( __U_SIGPARMS__ ) {
    uAbort( ": attempt to address location 0x%p.\n"
            "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript.",
          sfp->si_addr );
} // uSigHandlerModule::uSigSegvBusHandler


uSigHandlerModule::uSigHandlerModule() {
    // Associate handlers with the set of signals that this application is
    // interested in.  These handlers are inherited by all unix processes that
    // are subsequently created so they need not be installed again.

    uSSignal( SIGCHLD, uSigChldHandler, SA_SIGINFO );
    uSSignal( SIGHUP,  uSigTermHandler, SA_SIGINFO );
    uSSignal( SIGINT,  uSigTermHandler, SA_SIGINFO );
    uSSignal( SIGTERM, uSigTermHandler, SA_SIGINFO );
    uSSignal( SIGSEGV, uSigSegvBusHandler, SA_SIGINFO );
    uSSignal( SIGBUS,  uSigSegvBusHandler, SA_SIGINFO );

    // Do NOT specify SA_RESTART for SIGALRM because "select" does not wake up
    // when sent a SIGALRM from another UNIX process, which means non-blocking
    // I/O does not work correctly in multiprocessor mode.

    uSSignal( SIGALRM, uSigAlrmHandler, SA_SIGINFO );
} // uSigHandlerModule::uSigHandlerModule


// Local Variables: //
// compile-command: "gmake install" //
// End: //

Generated by  Doxygen 1.6.0   Back to index