197 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "syslib.h"
 | |
| #include <assert.h>
 | |
| #include <signal.h>
 | |
| #include <minix/sysutil.h>
 | |
| 
 | |
| /* SEF Signal callbacks. */
 | |
| PRIVATE struct sef_cbs {
 | |
|     sef_cb_signal_handler_t             sef_cb_signal_handler;
 | |
|     sef_cb_signal_manager_t             sef_cb_signal_manager;
 | |
| } sef_cbs = {
 | |
|     SEF_CB_SIGNAL_HANDLER_DEFAULT,
 | |
|     SEF_CB_SIGNAL_MANAGER_DEFAULT
 | |
| };
 | |
| 
 | |
| /* SEF Signal prototypes for sef_receive(). */
 | |
| PUBLIC _PROTOTYPE( int do_sef_signal_request, (message *m_ptr) );
 | |
| 
 | |
| /* Debug. */
 | |
| EXTERN _PROTOTYPE( char* sef_debug_header, (void) );
 | |
| 
 | |
| /* Information about SELF. */
 | |
| EXTERN endpoint_t sef_self_endpoint;
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *                         process_sigmgr_signals               	     *
 | |
|  *===========================================================================*/
 | |
| PRIVATE void process_sigmgr_signals(void)
 | |
| {
 | |
| /* A signal manager has pending signals in the kernel. Process them. */
 | |
|   endpoint_t target;
 | |
|   sigset_t sigset;
 | |
|   int signo, r;
 | |
| 
 | |
|   while (TRUE) {
 | |
|       /* Get an arbitrary pending signal. */
 | |
|       if((r=sys_getksig(&target, &sigset)) != OK)
 | |
|           panic("SEF: sys_getksig failed: %d", r);
 | |
| 
 | |
|       if (target == NONE) {
 | |
|           /* Stop if there are no more pending signals. */
 | |
|           break;
 | |
|       } else {
 | |
|           /* Process every signal in the signal set. */
 | |
|           r = OK;
 | |
|           for (signo = SIGS_FIRST; signo <= SIGS_LAST; signo++) {
 | |
|               if(sigismember(&sigset, signo)) {
 | |
|                   /* Let the callback code process the signal. */
 | |
|                   r = sef_cbs.sef_cb_signal_manager(target, signo);
 | |
| 
 | |
|                   /* Stop if process is gone. */
 | |
|                   if(r == EDEADSRCDST) {
 | |
|                       break;
 | |
|                   }
 | |
|               }
 | |
|           }
 | |
|           /* Tell the kernel we are done if the target is still alive. */
 | |
|           if(r == OK) {
 | |
|               if((r=sys_endksig(target)) != OK)
 | |
|                   panic("SEF: sys_endksig failed :%d", r);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *                         process_sigmgr_self_signals               	     *
 | |
|  *===========================================================================*/
 | |
| PRIVATE void process_sigmgr_self_signals(sigset_t sigset)
 | |
| {
 | |
| /* A signal manager has pending signals for itself. Process them. */
 | |
|   int signo;
 | |
| 
 | |
|   for (signo = SIGS_FIRST; signo <= SIGS_LAST; signo++) {
 | |
|       if(sigismember(&sigset, signo)) {
 | |
|           /* Let the callback code process the signal. */
 | |
|           sef_cbs.sef_cb_signal_handler(signo);
 | |
|       }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *                           do_sef_signal_request             		     *
 | |
|  *===========================================================================*/
 | |
| PUBLIC int do_sef_signal_request(message *m_ptr)
 | |
| {
 | |
| /* Handle a SEF Signal request. */
 | |
|   int signo;
 | |
|   sigset_t sigset;
 | |
| 
 | |
|   if(m_ptr->m_source == SYSTEM) {
 | |
|       /* Handle kernel signals. */
 | |
|       sigset = m_ptr->NOTIFY_ARG;
 | |
|       for (signo = SIGK_FIRST; signo <= SIGK_LAST; signo++) {
 | |
|           if (sigismember(&sigset, signo)) {
 | |
|               /* Let the callback code handle the kernel signal. */
 | |
|               sef_cbs.sef_cb_signal_handler(signo);
 | |
| 
 | |
|               /* Handle SIGKSIG for a signal manager. */
 | |
|               if(signo == SIGKSIG) {
 | |
|                   process_sigmgr_signals();
 | |
|               }
 | |
|               /* Handle SIGKSIGSM for a signal manager. */
 | |
|               else if(signo == SIGKSIGSM) {
 | |
|                   process_sigmgr_self_signals(sigset);
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|   }
 | |
|   else {
 | |
|       /* Handle system signals from a signal manager. */
 | |
|       signo = m_ptr->SIGS_SIG_NUM;
 | |
| 
 | |
|       /* Debug. */
 | |
| #if SEF_SIGNAL_DEBUG
 | |
|       sef_signal_debug_begin();
 | |
|       sef_signal_dprint("%s. Got a SEF Signal request for signal %d! About to handle signal.\n", 
 | |
|           sef_debug_header(), signo);
 | |
|       sef_signal_debug_end();
 | |
| #endif
 | |
| 
 | |
|       /* Let the callback code handle the signal. */
 | |
|       sef_cbs.sef_cb_signal_handler(signo);
 | |
|   }
 | |
| 
 | |
|   /* Return OK not to let anybody else intercept the request. */
 | |
|   return OK;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *                        sef_setcb_signal_handler                           *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void sef_setcb_signal_handler(sef_cb_signal_handler_t cb)
 | |
| {
 | |
|   assert(cb != NULL);
 | |
|   sef_cbs.sef_cb_signal_handler = cb;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *                        sef_setcb_signal_manager                           *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void sef_setcb_signal_manager(sef_cb_signal_manager_t cb)
 | |
| {
 | |
|   assert(cb != NULL);
 | |
|   sef_cbs.sef_cb_signal_manager = cb;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *       	          sef_cb_signal_handler_null                         *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void sef_cb_signal_handler_null(int signo)
 | |
| {
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *       	          sef_cb_signal_manager_null                         *
 | |
|  *===========================================================================*/
 | |
| PUBLIC int sef_cb_signal_manager_null(endpoint_t target, int signo)
 | |
| {
 | |
|   return OK;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *       	          sef_cb_signal_handler_term                         *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void sef_cb_signal_handler_term(int signo)
 | |
| {
 | |
|   /* Terminate in case of SIGTERM, ignore other signals. */
 | |
|   if(signo == SIGTERM) {
 | |
|       sef_exit(1);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *      	      sef_cb_signal_handler_posix_default                    *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void sef_cb_signal_handler_posix_default(int signo)
 | |
| {
 | |
|   switch(signo) {
 | |
|       /* Ignore when possible. */
 | |
|       case SIGCHLD:
 | |
|       case SIGWINCH:
 | |
|       case SIGCONT:
 | |
|       case SIGTSTP:
 | |
|       case SIGTTIN:
 | |
|       case SIGTTOU:
 | |
|       break;
 | |
| 
 | |
|       /* Terminate in any other case unless it is a kernel signal. */
 | |
|       default:
 | |
|           if(!IS_SIGK(signo)) {
 | |
|               sef_exit(1);
 | |
|           }
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | 
