📄 signal.c
字号:
/* Copyright (C) 1992-2000 the Florida State University Distributed by the Florida State University under the terms of the GNU Library General Public License.This file is part of Pthreads.Pthreads is free software; you can redistribute it and/ormodify it under the terms of the GNU Library General PublicLicense as published by the Free Software Foundation (version 2).Pthreads is distributed "AS IS" in the hope that it will beuseful, but WITHOUT ANY WARRANTY; without even the impliedwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU Library General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with Pthreads; see the file COPYING. If not, writeto the Free Software Foundation, 675 Mass Ave, Cambridge,MA 02139, USA.Report problems and direct all questions to: pthreads-bugs@ada.cs.fsu.edu @(#)signal.c 3.14 11/8/00*//* * Functions for the handling of signals and timers. *//* * The DEBUG flag causes a message to be printed out during signal handling. * The IO flag handles I/O requests asynchronously such that a signal is * delivered to the process upon completion of the operation. * If both flags are set at the same time, the signal handler would issue * an I/O request for each invocation which in turns causes another signal * to be delivered to yet another instance of the signal handler. * To avoid this, messages are only printed if DEBUG is defined but not IO. */#define PTHREAD_KERNEL#include "signal_internals.h"#include "internals.h"#include "setjmp.h"#include "offsets.h"#ifdef TDI_SUPPORT#include "tdi-aux.h"#endif#if !defined (_M_UNIX) && !defined (__dos__)//#include <sys/syscall.h>#endif#include <fsu_pthread/malloc.h>#include <fsu_pthread/debug.h>#include <asm-leon/kernel.h>#include <asm-leon/sigcontext.h>#ifdef NOERR_CHECK#undef NOERR_CHECK#include "mutex.h"#define NOERR_CHECK#else /* !NOERR_CHECK */#include "mutex.h"#endif /* NOERR_CHECK */#ifndef FC_CODE#define FC_CODE(c) (c & 0xff)#endif#ifndef __FDS_BITS#define __FDS_BITS(set) ((set)->fds_bits)#endif#ifdef STAND_ALONEextern char heap_start;#endif /* STAND_ALONE */#ifdef RAND_SWITCH extern int pthread_n_ready;#endif#if defined(STACK_CHECK) && defined(SIGNAL_STACK)extern int pthread_page_size;extern KERNEL_STACK pthread_tempstack;#endif#ifdef STAND_ALONE//pthread_timer_q_t pthread_timer; /* timer queue */#elsepthread_timer_q pthread_timer; /* timer queue */static struct itimerval it; /* timer structure */#endifstruct sigaction pthread_user_handler[NNSIG]; /* user signal handlers */volatile int new_code[NNSIG]; /* UNIX signal code (new sigs) */pthread_cond_t *new_cond[NNSIG]; /* cond for user handlers */struct context_t *new_scp[NNSIG]; /* info for user handlers */static int pending_code[NNSIG]; /* UNIX signal code (pending) */static sigset_t synchronous; /* set of synchronous signals */static sigset_t sig_handling; /* set of signals being handled*//*------------------------------------------------------------*//* * default_action - take default action on process * Notice: SIGSTOP and SIGKILL can never be received (unmaskable) * but they are included anyway. */static void default_action(sig) int sig;{ PTRACEIN; switch (sig) { case SIGURG: case SIGIO: case SIGCONT: case SIGCHLD: case SIGWINCH: break; /* ignore or continue */ case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: PDEBUG(PDBG_SIGNAL,"default action exit"); exit(0); break; default: PDEBUG(PDBG_SIGNAL,"default action exit"); exit(0); }}/*------------------------------------------------------------*//* * handle_thread_signal - try to handle one signal on a thread and * return TRUE if it was handled, otherwise return FALSE */static int handle_thread_signal(p, sig, code)pthread_t p;int sig;int code;{ register struct context_t *scp;#ifdef C_CONTEXT_SWITCH extern void pthread_fake_call_wrapper_wrapper();#endif /* C_CONTEXT_SWITCH */ PTRACEIN; PDEBUG(PDBG_SIGNAL,"thread:0x%x sig:%d code:0x%x",p, sig, code); /* * handle timer signals */ if (sig == TIMER_SIG) { } /* * handle signals for sigwait */ if (p->state & T_SIGWAIT && sigismember(&p->sigwaitset, sig)) { pthread_q_wakeup_thread(NO_QUEUE, p, NO_QUEUE_INDEX); p->state &= ~T_SIGWAIT; pthread_sigaddset2set(&p->mask, &p->sigwaitset); pthread_sigdelset2set(&p->mask, &cantmask); sigdelset(&p->sigwaitset, sig); } /* * handler set to ignore */ if (pthread_user_handler[sig].sa_handler == SIG_IGN && sig != SIGCANCEL) { PDEBUG(PDBG_SIGNAL,"ignore %d ",sig); return(TRUE); } /* * handler set to default action */ if (pthread_user_handler[sig].sa_handler == SIG_DFL && sig != SIGCANCEL) { PDEBUG(PDBG_SIGNAL,"default_action[%d] ",sig); default_action(sig); return(TRUE); } /* * handle signals for sigsuspend and user handlers */ if (sigismember(&handlerset, sig)) { if (p->state & T_BLOCKED) { if (p->pt_reentp) { p->pt_reentp->_errno = EINTR; } } if (!(p->state & T_RUNNING)) { if (p->state & T_SYNCTIMER) { PDEBUG(PDBG_TIMEOUT,": timeout on sigtimedwait\n"); pthread_cancel_timed_sigwait(p, TRUE, SYNC_TIME, TRUE); } else { pthread_q_wakeup_thread(p->queue, p, PRIMARY_QUEUE); if (p->state & (T_SIGWAIT | T_SIGSUSPEND)) { p->state &= ~(T_SIGWAIT | T_SIGSUSPEND); sigemptyset(&p->sigwaitset); } } } p->sig_info[sig].si_signo = sig;#if (defined(STACK_CHECK) && defined(SIGNAL_STACK)) if ((sig == SIGSEGV || sig == SIGBUS) && FC_CODE(code) != code) { p->sig_info[sig].si_value.sigval_ptr = (caddr_t) code; p->sig_info[sig].si_code = FC_PROT; } else#endif /* STACK_CHECK && SIGNAL_STACK */ p->sig_info[sig].si_code = code; PDEBUG(PDBG_SIGNAL,"signal %d",sig);#ifdef TRASH /* * return avoids a loop in thread signal processing, no other solution */ if (p->context[THREAD_JB_PC] == (int) pthread_fake_call_wrapper_wrapper) { /* * We must mark the signal as pending!!! */ return TRUE; }#endif if (pthread_not_called_from_sighandler(p->context[THREAD_JB_PC])){ PDEBUG(PDBG_SIGNAL,"DIRECTED_AT_THREAD"); p->nscp = (struct context_t *) DIRECTED_AT_THREAD; } p->sig = sig; p->osp = p->context[THREAD_JB_SP]; p->opc = p->context[THREAD_JB_PC]; PDEBUG(PDBG_SIGNAL,"old context sp: 0x%x pc: 0x%x (%x,%x)",p->osp, p->opc,&p->osp, &p->opc); p->context[THREAD_JB_PC] = (int) pthread_fake_call_wrapper_wrapper; p->opc += RETURN_OFFSET; p->context[THREAD_JB_PC] -= RETURN_OFFSET; PDEBUG(PDBG_SIGNAL,"initialized",p, sig, code); return(TRUE); } /* * handle cancel signal */ if (sig == SIGCANCEL) { if (p->state & T_SYNCTIMER) pthread_cancel_timed_sigwait(p, FALSE, ALL_TIME, TRUE); else if (p->state & (T_SIGWAIT | T_SIGSUSPEND)) { p->state &= ~(T_SIGWAIT | T_SIGSUSPEND); sigemptyset(&p->sigwaitset); } if (p->queue && !(p->state & T_RUNNING)) pthread_q_deq(p->queue, p, PRIMARY_QUEUE); TAILQ_REMOVE(&all,p,pt_qelem[K_QUEUES_ALL]); /* * no more signals for this thread, not even cancellation signal */ pthread_sigcpyset2set(&p->mask, &all_signals); sigaddset(&p->mask, SIGCANCEL); p->nscp = (struct context_t *) DIRECTED_AT_THREAD; p->sig = (int) PTHREAD_CANCELED; p->context[THREAD_JB_PC] = (int) pthread_fake_call_wrapper_wrapper; p->context[THREAD_JB_PC] -= RETURN_OFFSET; if (!(p->state & T_RUNNING)) pthread_q_wakeup_thread(NO_QUEUE, p, NO_QUEUE_INDEX); return(TRUE); } return (FALSE);}/*------------------------------------------------------------*//* * handle_one_signal - handle one signal on the process level * assumes SET_KERNEL_FLAG */static void handle_one_signal(sig, code)int sig;int code;{ register pthread_t p = mac_pthread_self(); struct itimerval it; struct timespec now; extern pthread_t pthread_q_all_find_receiver(); static int aio_handle(); PTRACEIN; PDEBUG(PDBG_SIGNAL,"sig:%d code:0x%x",sig, code); /* * Determine who needs to get the signal (in the following order): * (1) signal directed at specific thread: take this thread * (2) signal at process level: * (2a) synchronous signal: direct at current thread * (2b) SIGALRM, timer queue not empty, timer expired: take head off timer q * (2c) SIGIO, asynchronous I/O requested: determine receiver and make ready * (2c) handler defined: take first thread in all queue with signal unmasked * (3) no handler defined: pend signal on process till thread unmasks signal * if signal already pending, it's lost */ if (p != NO_PTHREAD && (p->nscp == DIRECTED_AT_THREAD || pthread_not_called_from_sighandler(p->context[THREAD_JB_PC])) && (p = (pthread_t) code)) code = SI_USER; else if (p != NO_PTHREAD && sigismember(&synchronous, sig)) /* p = p */; else if (sig == SIGALRM) { /* eiselekd todo: fix later */ /*if ((p = pthread_timer) && !clock_gettime(CLOCK_REALTIME, &now) && GTEQ_NTIME(now, p->tp)) pthread_cancel_timed_sigwait(p, TRUE, ANY_TIME, p->queue != &ready); */ return; } /* SIGIO is being used to invoke pthread_select_isr which takes care of * suspending and waking up threads waiting on I/O. * The parameter 2 is used instead of UART_ISR */ else if (sig == SIGIO) { //pthread_select_isr(SIGIO); return; } else if (!(p = pthread_q_all_find_receiver(&all, sig))) { if (!sigismember(&pending_signals, sig)) { sigaddset(&pending_signals, sig); pending_code[sig] = code; } return; } if (p->state & T_RETURNED) return; /* * Pend signal on thread if it's masked out OR * if the signal is SIGCANCEL, the interrupt state CONTROLLED, and * we are not at an interruption point. */ if (sigismember(&p->mask, sig) || sig == SIGCANCEL && p->state & T_CONTROLLED && !(p->state & T_INTR_POINT)) { sigaddset(&p->pending, sig); p->sig_info[sig].si_code = code; return; } if (handle_thread_signal(p, sig, code)) return; default_action(sig);} /*------------------------------------------------------------*//* * pthread_handle_many_process_signals - determine pending signal(s). * if no thread ready, suspend process; * returns the head of the ready queue. * assumes SET_KERNEL_FLAG */pthread_t pthread_handle_many_process_signals(){ register int sig; PTRACEIN; do { while (pthread_signonemptyset(&new_signals)) { /* * start critical section */ SIGPROCMASK(SIG_BLOCK, &all_signals, (struct sigset_t *) NULL); pthread_sigcpyset2set(&sig_handling, &new_signals); pthread_sigdelset2set(&new_signals, &sig_handling); SIGPROCMASK(SIG_UNBLOCK, &all_signals, (struct sigset_t *) NULL); /* * end of critical section */ for (sig = 1; sig < NNSIG; sig++) if (sigismember(&sig_handling, sig)) handle_one_signal(sig, new_code[sig]); } /* * No thread, no action: suspend waiting for signal at process level */ if (TAILQ_EMPTY(&ready)) { SIGPROCMASK(SIG_BLOCK, &all_signals, (struct sigset_t *) NULL); if (!pthread_signonemptyset(&new_signals)) { while(!pthread_signonemptyset(&new_signals)) SIGSUSPEND(&no_signals); } SIGPROCMASK(SIG_UNBLOCK, &all_signals, (struct sigset_t *) NULL); } } while (TAILQ_EMPTY(&ready)); return(TAILQ_FIRST(&ready));}/*------------------------------------------------------------*//* * pthread_handle_one_process_signal - handle latest signal caught by * universal handler while not in kernel * returns the head of the ready queue. * assumes SET_KERNEL_FLAG */void pthread_handle_one_process_signal(sig, code)int sig;int code;{ PTRACEIN; handle_one_signal(sig, code); if (pthread_signonemptyset(&new_signals) || TAILQ_EMPTY(&ready)) pthread_handle_many_process_signals();}/*------------------------------------------------------------*//* * pthread_handle_pending_signals - handle unmasked pending signals of * current thread assumes SET_KERNEL_FLAG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -