📄 signal.cxx
字号:
// the one supplied.
sigset_t old = self->sigmask;
self->sigmask = *set;
// Loop until a signal gets delivered
while( !cyg_deliver_signals() )
signal_sigwait.wait();
self->sigmask = old;
signal_mutex.unlock();
SIGNAL_RETURN(EINTR);
}
// -------------------------------------------------------------------------
// Wait for a signal in set to arrive
// Implement this as a variant on sigtimedwait().
externC int sigwait (const sigset_t *set, int *sig)
{
SIGNAL_ENTRY();
siginfo_t info;
int ret = sigtimedwait( set, &info, NULL );
if( ret == -1 )
SIGNAL_RETURN(errno);
*sig = ret;
SIGNAL_RETURN(0);
}
// -------------------------------------------------------------------------
// Do the same as sigwait() except return a siginfo_t object too.
// Implement this as a variant on sigtimedwait().
externC int sigwaitinfo (const sigset_t *set, siginfo_t *info)
{
SIGNAL_ENTRY();
int ret = sigtimedwait( set, info, NULL );
SIGNAL_RETURN_VALUE(ret);
}
// -------------------------------------------------------------------------
// Wait either for a signal in the given set to become pending, or
// for the timeout to expire. If timeout is NULL, wait for ever.
externC int sigtimedwait (const sigset_t *set, siginfo_t *info,
const struct timespec *timeout)
{
SIGNAL_ENTRY();
// check for cancellation first.
pthread_testcancel();
int err = 0;
cyg_tick_count ticks;
if( timeout == NULL ) ticks = 0;
else ticks = cyg_timespec_to_ticks( timeout ) +
Cyg_Clock::real_time_clock->current_value();
pthread_info *self = pthread_self_info();
signal_mutex.lock();
sigset_t todo;
// Wait for a signal in the set to become pending
while( (todo = (*set & (sig_pending | self->sigpending))) == 0 )
{
// If timeout is not NULL, do a timed wait on the
// sigwait condition variable. If it is NULL - wait
// until we are woken.
if( timeout )
{
if( ticks == 0 || !signal_sigwait.wait(ticks) )
{
// If the timeout is actually zero, or we have waited and
// timed out, then we must quit with an error.
err = EAGAIN;
break;
}
}
else {
if ( !signal_sigwait.wait() ) {
// check we weren't woken up forcibly (e.g. to be cancelled)
// if so, pretend it's an error
err = EAGAIN;
break;
}
}
// Special case check for SIGALRM since the fact SIGALRM is masked
// would have prevented it being set pending in the alarm handler.
check_sigalarm();
cyg_posix_timer_asr(self);
}
if( err == 0 )
{
// There is a signal in the set that is pending: deliver
// it. todo contains a mask of all the signals that could be
// delivered now, but we only want to deliver one of them.
int signo = 0;
// Select the lowest numbered signal from the todo mask
HAL_LSBIT_INDEX( signo, todo );
signal_state *ss = &sigstate[signo];
sigset_t sigbit = 1L<<signo;
if( (ss->sa.sa_flags & SA_SIGINFO) && (ss->pending != NULL) )
{
// If the SA_SIGINFO bit is set, then there
// will be a signal_info object queued on the
// pending field.
signal_info *si = ss->pending->next;
*info = 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;
si->next = siginfo_next;
siginfo_next = si;
}
else
{
// Not a queued signal, or there is no signal_info object
// on the pending queue: fill in info structure with
// default values.
info->si_signo = signo;
info->si_code = SI_USER;
info->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.
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;
}
// all done
}
signal_mutex.unlock();
pthread_testcancel();
if (err)
SIGNAL_RETURN(err);
else
SIGNAL_RETURN_VALUE( info->si_signo );
}
//==========================================================================
// alarm, pause and sleep
// -------------------------------------------------------------------------
// Generate SIGALRM after some number of seconds
externC unsigned int alarm( unsigned int seconds )
{
int res = 0;
struct timespec tv;
cyg_tick_count trigger, interval;
SIGNAL_ENTRY();
signal_mutex.lock();
if( sigalrm_armed )
{
sigalrm_alarm.disable();
sigalrm_alarm.get_times( &trigger, &interval );
// Convert trigger time back to interval
trigger -= Cyg_Clock::real_time_clock->current_value();
cyg_ticks_to_timespec( trigger, &tv );
res = tv.tv_sec;
sigalrm_armed = false;
}
if( seconds != 0 )
{
// Here we know that the sigalrm_alarm is unarmed, set it up
// to trigger in the required number of seconds.
tv.tv_sec = seconds;
tv.tv_nsec = 0;
trigger = cyg_timespec_to_ticks( &tv );
// Convert trigger interval to absolute time
trigger += Cyg_Clock::real_time_clock->current_value();
sigalrm_alarm.initialize( trigger, 0 );
sigalrm_armed = true;
}
signal_mutex.unlock();
CYG_REPORT_RETVAL(res);
return res;
}
// -------------------------------------------------------------------------
// Wait for a signal to be delivered.
externC int pause( void )
{
SIGNAL_ENTRY();
signal_mutex.lock();
// Check for any pending signals that can be delivered and
// if there are none, wait for a signal to be generated
if( !cyg_deliver_signals() )
signal_sigwait.wait();
// Now check again for some signals to deliver
cyg_deliver_signals();
signal_mutex.unlock();
SIGNAL_RETURN(EINTR);
}
//==========================================================================
// Signal sets
// -------------------------------------------------------------------------
// Clear all signals from set.
externC int sigemptyset (sigset_t *set)
{
SIGNAL_ENTRY();
*set = 0;
SIGNAL_RETURN(0);
}
// -------------------------------------------------------------------------
// Set all signals in set.
externC int sigfillset (sigset_t *set)
{
SIGNAL_ENTRY();
*set = ~0;
SIGNAL_RETURN(0);
}
// -------------------------------------------------------------------------
// Add signo to set.
externC int sigaddset (sigset_t *set, int signo)
{
SIGNAL_ENTRY();
int err = 0;
if( !SIGNAL_VALID(signo) )
err = EINVAL;
else *set |= 1<<signo;
SIGNAL_RETURN(err);
}
// -------------------------------------------------------------------------
// Remove signo from set.
externC int sigdelset (sigset_t *set, int signo)
{
SIGNAL_ENTRY();
int err = 0;
if( !SIGNAL_VALID(signo) )
err = EINVAL;
else *set &= ~(1<<signo);
SIGNAL_RETURN(err);
}
// -------------------------------------------------------------------------
// Test whether signo is in set
externC int sigismember (const sigset_t *set, int signo)
{
SIGNAL_ENTRY();
int ret = 0;
if( !SIGNAL_VALID(signo) )
SIGNAL_RETURN(EINVAL);
if( *set & (1<<signo) ) ret = 1;
CYG_REPORT_RETVAL( ret );
return ret;
}
//==========================================================================
// ISO C compatibility functions
// -------------------------------------------------------------------------
// Installs a new signal handler for the specified signal, and returns
// the old handler
externC sa_sighandler_t signal(int sig, sa_sighandler_t handler)
{
SIGNAL_ENTRY();
int err;
sa_sighandler_t ret;
struct sigaction new_action;
struct sigaction old_action;
sigemptyset( &new_action.sa_mask );
new_action.sa_flags = 0;
new_action.sa_handler = handler;
err = sigaction( sig, &new_action, &old_action );
if( err < 0 )
ret = SIG_ERR;
else ret = old_action.sa_handler;
CYG_REPORT_RETVAL( ret );
return ret;
}
// -------------------------------------------------------------------------
// raise() - ISO C 7.7.2 //
//
// Raises the signal, which will cause the current signal handler for
// that signal to be called
externC int raise(int sig)
{
return kill( 0, sig );
}
// -------------------------------------------------------------------------
// siglongjmp()
// Restores signal mask and longjumps.
__externC void siglongjmp( sigjmp_buf env, int val )
{
CYG_REPORT_FUNCNAME( "siglongjmp" );
CYG_REPORT_FUNCARG2( "&env=%08x, val=%d", &env, val );
// ISO C says that if we are passed val == 0, then we change it to 1
if( val == 0 )
val = 1;
if( env[0].__savemask )
pthread_sigmask( SIG_SETMASK, &env[0].__sigsavemask, NULL );
HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering
hal_longjmp( env[0].__jmp_buf, val );
HAL_REORDER_BARRIER(); // prevent any chance of optimisation re-ordering
#ifdef CYGDBG_USE_ASSERTS
CYG_ASSERT( 0, "siglongjmp should not have reached this point!" );
#else
for (;;)
CYG_EMPTY_STATEMENT;
#endif
}
#endif // ifdef CYGPKG_POSIX_SIGNALS
// -------------------------------------------------------------------------
// EOF signal.cxx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -