signal.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:18k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* ==== signal.c ============================================================
  2.  * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *  This product includes software developed by Chris Provenzano.
  16.  * 4. The name of Chris Provenzano may not be used to endorse or promote 
  17.  *   products derived from this software without specific prior written
  18.  *   permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
  21.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED.  IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY 
  24.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  26.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  28.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  30.  * SUCH DAMAGE.
  31.  *
  32.  * Description : Queue functions.
  33.  *
  34.  *  1.00 93/07/21 proven
  35.  *      -Started coding this file.
  36.  */
  37. #ifndef lint
  38. static const char rcsid[] = "$Id$";
  39. #endif
  40. #include <config.h>
  41. #include <pthread.h>
  42. #include <signal.h>
  43. /* This will force init.o to get dragged in; if you've got support for
  44.    C++ initialization, that'll cause pthread_init to be called at
  45.    program startup automatically, so the application won't need to
  46.    call it explicitly.  */
  47. extern char __pthread_init_hack;
  48. char *__pthread_init_hack_2 = &__pthread_init_hack;
  49. /*
  50.  * Time which select in fd_kern_wait() will sleep.
  51.  * If there are no threads to run we sleep for an hour or until
  52.  * we get an interrupt or an fd thats awakens. To make sure we
  53.  * don't miss an interrupt this variable gets reset too zero in
  54.  * sig_handler_real().
  55.  */
  56. struct timeval __fd_kern_wait_timeout = { 0, 0 };
  57. /*
  58.  * Global for user-kernel lock, and blocked signals
  59.  */
  60. static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, };
  61. volatile sig_atomic_t sig_to_process = 0;
  62. /* static volatile sigset_t sig_to_process; */
  63. static volatile int sig_count = 0;
  64. static void sig_handler(int signal);
  65. static void set_thread_timer();
  66. static void __cleanup_after_resume( void );
  67. void sig_prevent(void);
  68. void sig_resume(void);
  69. /* ==========================================================================
  70.  * context_switch()
  71.  *
  72.  * This routine saves the current state of the running thread gets
  73.  * the next thread to run and restores it's state. To allow different
  74.  * processors to work with this routine, I allow the machdep_restore_state()
  75.  * to either return or have it return from machdep_save_state with a value
  76.  * other than 0, this is for implementations which use setjmp/longjmp. 
  77.  */
  78. static void context_switch()
  79. {
  80. struct pthread **current, *next, *last, **dead;
  81. if (pthread_run->state == PS_RUNNING) {
  82. /* Put current thread back on the queue */
  83. pthread_prio_queue_enq(pthread_current_prio_queue, pthread_run);
  84. }
  85. /* save floating point registers if necessary */
  86. if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) {
  87. machdep_save_float_state(pthread_run);
  88. }
  89. /* save state of current thread */
  90. if (machdep_save_state()) {
  91. return;
  92. }
  93. last = pthread_run;
  94. /* Poll all fds */
  95. fd_kern_poll();
  96. context_switch_reschedule:;
  97. /* Are there any threads to run */
  98. if (pthread_run = pthread_prio_queue_deq(pthread_current_prio_queue)) {
  99. /* restore floating point registers if necessary */
  100. if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) {
  101. machdep_restore_float_state();
  102. }
  103. uthread_sigmask = &(pthread_run->sigmask);
  104.        /* restore state of new current thread */
  105. machdep_restore_state();
  106.      return;
  107.     } 
  108. /* Are there any threads at all */
  109. for (next = pthread_link_list; next; next = next->pll) {
  110. if ((next->state != PS_UNALLOCED) && (next->state != PS_DEAD)) {
  111. sigset_t sig_to_block, oset;
  112. sigfillset(&sig_to_block);
  113. /*
  114.  * Check sig_to_process before calling fd_kern_wait, to handle
  115.  * things like zero timeouts to select() which would register
  116.  * a signal with the sig_handler_fake() call.
  117.  *
  118.  * This case should ignore SIGVTALRM
  119.  */
  120. machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
  121. signum_to_process[SIGVTALRM] = 0;
  122. if (sig_to_process) {
  123.                /* Process interrupts */
  124.                 /*
  125.                  * XXX pthread_run should not be set!
  126.  * Places where it dumps core should be fixed to 
  127.  * check for the existance of pthread_run --proven
  128.                  */
  129.                 sig_handler(0);
  130.             } else {
  131. machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
  132. /*
  133.  * Do a wait, timeout is set to a hour unless we get an 
  134.  * intr. before the select in wich case it polls.
  135.  */
  136. fd_kern_wait();
  137. machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
  138. /* Check for interrupts, but ignore SIGVTALR */
  139. signum_to_process[SIGVTALRM] = 0;
  140. if (sig_to_process) {
  141. /* Process interrupts */
  142. sig_handler(0); 
  143. }
  144. }
  145. machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); 
  146. goto context_switch_reschedule;
  147. }
  148. }
  149. /* There are no threads alive. */
  150. pthread_run = last;
  151. exit(0);
  152. }
  153. #if !defined(HAVE_SYSCALL_SIGSUSPEND) && defined(HAVE_SYSCALL_SIGPAUSE)
  154. /* ==========================================================================
  155.  * machdep_sys_sigsuspend()
  156.  */ 
  157. int machdep_sys_sigsuspend(sigset_t * set)
  158. {
  159. return(machdep_sys_sigpause(* set));
  160. }
  161. #endif
  162. /* ==========================================================================
  163.  * sig_handler_pause()
  164.  * 
  165.  * Wait until a signal is sent to the process.
  166.  */
  167. void sig_handler_pause()
  168. {
  169. sigset_t sig_to_block, sig_to_pause, oset;
  170. sigfillset(&sig_to_block);
  171. sigemptyset(&sig_to_pause);
  172. machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset);
  173. /* if (!(SIG_ANY(sig_to_process))) { */
  174. if (!sig_to_process) {
  175. machdep_sys_sigsuspend(&sig_to_pause);
  176. }
  177. machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset);
  178. }
  179. /* ==========================================================================
  180.  * context_switch_done()
  181.  *
  182.  * This routine does all the things that are necessary after a context_switch()
  183.  * calls the machdep_restore_state(). DO NOT put this in the context_switch()
  184.  * routine because sometimes the machdep_restore_state() doesn't return
  185.  * to context_switch() but instead ends up in machdep_thread_start() or
  186.  * some such routine, which will need to call this routine and
  187.  * sig_check_and_resume().
  188.  */
  189. void context_switch_done()
  190. {
  191. /* sigdelset((sigset_t *)&sig_to_process, SIGVTALRM); */
  192. signum_to_process[SIGVTALRM] = 0;
  193. set_thread_timer();
  194. }
  195. /* ==========================================================================
  196.  * set_thread_timer()
  197.  *
  198.  * Assums kernel is locked.
  199.  */
  200. static void set_thread_timer()
  201. {
  202. static int last_sched_attr = SCHED_RR;
  203. switch (pthread_run->attr.schedparam_policy) {
  204. case SCHED_RR:
  205. machdep_set_thread_timer(&(pthread_run->machdep_data));
  206. break;
  207. case SCHED_FIFO:
  208. if (last_sched_attr != SCHED_FIFO) {
  209. machdep_unset_thread_timer(NULL);
  210. }
  211. break;
  212. case SCHED_IO:
  213. if ((last_sched_attr != SCHED_IO) && (!sig_count)) {
  214. machdep_set_thread_timer(&(pthread_run->machdep_data));
  215. }
  216. break;
  217. default:
  218. machdep_set_thread_timer(&(pthread_run->machdep_data));
  219. break;
  220.     last_sched_attr = pthread_run->attr.schedparam_policy;
  221. }
  222. /* ==========================================================================
  223.  * sigvtalrm()
  224.  */
  225. static inline void sigvtalrm() 
  226. {
  227. if (sig_count) {
  228. sigset_t sigall, oset;
  229. sig_count = 0;
  230. /* Unblock all signals */
  231. sigemptyset(&sigall);
  232. machdep_sys_sigprocmask(SIG_SETMASK, &sigall, &oset); 
  233. }
  234. context_switch();
  235. context_switch_done();
  236. }
  237. /* ==========================================================================
  238.  * sigdefault()
  239.  */
  240. static inline void sigdefault(int sig)
  241. {
  242. int ret;
  243. ret = pthread_sig_register(sig);
  244. if (pthread_run && (ret > pthread_run->pthread_priority)) {
  245. sigvtalrm();
  246. }
  247. }
  248. /* ==========================================================================
  249.  * sig_handler_switch()
  250.  */
  251. static inline void sig_handler_switch(int sig)
  252. {
  253. int ret;
  254. switch(sig) {
  255. case 0:
  256. break;
  257. case SIGVTALRM:
  258. sigvtalrm();
  259. break;
  260. case SIGALRM:
  261. /* sigdelset((sigset_t *)&sig_to_process, SIGALRM); */
  262. signum_to_process[SIGALRM] = 0;
  263. switch (ret = sleep_wakeup()) {
  264. default:
  265. if (pthread_run && (ret > pthread_run->pthread_priority)) {
  266. sigvtalrm();
  267. }
  268. case 0:
  269. break;
  270. case NOTOK:
  271. /* Do the registered action, no threads were sleeping */
  272.                                       /* There is a timing window that gets
  273.                                        * here when no threads are on the
  274.                                        * sleep queue.  This is a quick fix.
  275.                                        * The real problem is possibly related
  276.                                        * to heavy use of condition variables
  277.                                        * with time outs.
  278.                                        * (mevans)
  279.                                        *sigdefault(sig);
  280.                                        */
  281.   break;
  282. }
  283. break;
  284. case SIGCHLD:
  285. /* sigdelset((sigset_t *)&sig_to_process, SIGCHLD); */
  286. signum_to_process[SIGCHLD] = 0;
  287. switch (ret = wait_wakeup()) {
  288. default:
  289. if (pthread_run && (ret > pthread_run->pthread_priority)) {
  290. sigvtalrm();
  291. }
  292. case 0:
  293. break;
  294. case NOTOK:
  295. /* Do the registered action, no threads were waiting */
  296. sigdefault(sig);
  297. break;
  298. break;
  299. #ifdef SIGINFO
  300. case SIGINFO:
  301. pthread_dump_info ();
  302. /* Then fall through, invoking the application's
  303.     signal handler after printing our info out.
  304.     I'm not convinced that this is right, but I'm not
  305.     100% convinced that it is wrong, and this is how
  306.     Chris wants it done...  */
  307. #endif
  308. default:
  309. /* Do the registered action */
  310. if (!sigismember(uthread_sigmask, sig)) {
  311. /*
  312.  * If the signal isn't masked by the last running thread and
  313.  * the signal behavior is default or ignore then we can
  314.  * execute it immediatly. --proven
  315.  */
  316. pthread_sig_default(sig);
  317. }
  318. signum_to_process[sig] = 0;
  319. sigdefault(sig);
  320. break;
  321. }
  322. }
  323. /* ==========================================================================
  324.  * sig_handler()
  325.  *
  326.  * Process signal that just came in, plus any pending on the signal mask.
  327.  * All of these must be resolved.
  328.  *
  329.  * Assumes the kernel is locked. 
  330.  */
  331. static void sig_handler(int sig)
  332. {
  333. if (pthread_kernel_lock != 1) {
  334. PANIC();
  335. }
  336. if (sig) { 
  337. sig_handler_switch(sig);
  338. }
  339. while (sig_to_process) {
  340. for (sig_to_process = 0, sig = 1; sig <= SIGMAX; sig++) {
  341. if (signum_to_process[sig]) {
  342. sig_handler_switch(sig);
  343. }
  344. }
  345. }
  346. /*
  347. if (SIG_ANY(sig_to_process)) {
  348. for (sig = 1; sig <= SIGMAX; sig++) {
  349. if (sigismember((sigset_t *)&sig_to_process, sig)) {
  350. goto sig_handler_top;
  351. }
  352. }
  353. }
  354. */
  355. }
  356. /* ==========================================================================
  357.  * sig_handler_real()
  358.  * 
  359.  * On a multi-processor this would need to use the test and set instruction
  360.  * otherwise the following will work.
  361.  */
  362. void sig_handler_real(int sig)
  363. {
  364. /*
  365.  * Get around systems with BROKEN signal handlers.
  366.  *
  367.  * Some systems will reissue SIGCHLD if the handler explicitly
  368.  * clear the signal pending by either doing a wait() or 
  369.  * ignoring the signal.
  370.  */
  371. #if defined BROKEN_SIGNALS
  372. if (sig == SIGCHLD) {
  373. sigignore(SIGCHLD);
  374. signal(SIGCHLD, sig_handler_real);
  375. }
  376. #endif
  377. if (pthread_kernel_lock) {
  378. /* sigaddset((sigset_t *)&sig_to_process, sig); */
  379. __fd_kern_wait_timeout.tv_sec = 0;
  380. signum_to_process[sig] = 1;
  381. sig_to_process = 1;
  382. return;
  383. }
  384. pthread_kernel_lock++;
  385. sig_count++;
  386. sig_handler(sig);
  387. /* Handle any signals the current thread might have just gotten */
  388. if (pthread_run && pthread_run->sigcount) {
  389. pthread_sig_process();
  390. }
  391. pthread_kernel_lock--;
  392. }
  393. /* ==========================================================================
  394.  * sig_handler_fake()
  395.  */
  396. void sig_handler_fake(int sig)
  397. {
  398. if (pthread_kernel_lock) {
  399. /* sigaddset((sigset_t *)&sig_to_process, sig); */
  400. signum_to_process[sig] = 1;
  401. sig_to_process = 1;
  402. return;
  403. }
  404. pthread_kernel_lock++;
  405. sig_handler(sig);
  406. while (!(--pthread_kernel_lock)) {
  407. if (sig_to_process) {
  408. /* if (SIG_ANY(sig_to_process)) { */
  409. pthread_kernel_lock++;
  410. sig_handler(0);
  411. } else {
  412. break;
  413. }
  414. }
  415. }
  416. /* ==========================================================================
  417.  * __pthread_signal_delete(int sig)
  418.  *
  419.  * Assumes the kernel is locked.
  420.  */
  421. void __pthread_signal_delete(int sig)
  422. {
  423. signum_to_process[sig] = 0;
  424. }
  425. /* ==========================================================================
  426.  * pthread_sched_other_resume()
  427.  *
  428.  * Check if thread to be resumed is of higher priority and if so
  429.  * stop current thread and start new thread.
  430.  */
  431. pthread_sched_other_resume(struct pthread * pthread)
  432. {
  433. pthread->state = PS_RUNNING;
  434. pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
  435. if (pthread->pthread_priority > pthread_run->pthread_priority) {
  436. if (pthread_kernel_lock == 1) {
  437. sig_handler(SIGVTALRM);
  438. }
  439. }
  440. __cleanup_after_resume();
  441. }
  442. /* ==========================================================================
  443.  * pthread_resched_resume()
  444.  *
  445.  * This routine assumes that the caller is the current pthread, pthread_run
  446.  * and that it has a lock the kernel thread and it wants to reschedule itself.
  447.  */
  448. void pthread_resched_resume(enum pthread_state state)
  449. {
  450. pthread_run->state = state;
  451. /* Since we are about to block this thread, lets see if we are
  452.  * at a cancel point and if we've been cancelled.
  453.  * Avoid cancelling dead or unalloced threads.
  454.  */
  455. if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) &&
  456. TEST_PTHREAD_IS_CANCELLABLE(pthread_run) &&
  457. state != PS_DEAD && state != PS_UNALLOCED ) {
  458. /* Set this flag to avoid recursively calling pthread_exit */
  459. /* We have to set this flag here because we will unlock the
  460.  * kernel prior to calling pthread_cancel_internal.
  461.  */
  462. SET_PF_RUNNING_TO_CANCEL(pthread_run);
  463. pthread_run->old_state = state; /* unlock needs this data */
  464. pthread_sched_resume(); /* Unlock kernel before cancel */
  465. pthread_cancel_internal( 1 ); /* free locks and exit */
  466. }
  467. sig_handler(SIGVTALRM);
  468. __cleanup_after_resume();
  469. }
  470. /* ==========================================================================
  471.  * pthread_sched_resume()
  472.  */
  473. void pthread_sched_resume()
  474. {
  475. __cleanup_after_resume();
  476. }
  477. /*----------------------------------------------------------------------
  478.  * Function: __cleanup_after_resume
  479.  * Purpose: cleanup kernel locks after a resume
  480.  * Args: void
  481.  * Returns: void
  482.  * Notes:
  483.  *----------------------------------------------------------------------*/
  484. static void
  485. __cleanup_after_resume( void )
  486. {
  487. /* Only bother if we are truely unlocking the kernel */
  488. while (!(--pthread_kernel_lock)) {
  489. /* if (SIG_ANY(sig_to_process)) { */
  490. if (sig_to_process) {
  491. pthread_kernel_lock++;
  492. sig_handler(0);
  493. continue;
  494. }
  495. if (pthread_run && pthread_run->sigcount) {
  496. pthread_kernel_lock++;
  497. pthread_sig_process();
  498. continue;
  499. }
  500. break;
  501. }
  502. if( pthread_run == NULL )
  503. return; /* Must be during init processing */
  504. /* Test for cancel that should be handled now */
  505. if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) &&
  506. TEST_PTHREAD_IS_CANCELLABLE(pthread_run) ) {
  507. /* Kernel is already unlocked */
  508. pthread_cancel_internal( 1 ); /* free locks and exit */
  509. }
  510. }
  511. /* ==========================================================================
  512.  * pthread_sched_prevent()
  513.  */
  514. void pthread_sched_prevent(void)
  515. {
  516. pthread_kernel_lock++;
  517. }
  518. /* ==========================================================================
  519.  * sig_init()
  520.  *
  521.  * SIGVTALRM (NOT POSIX) needed for thread timeslice timeouts.
  522.  * Since it's not POSIX I will replace it with a 
  523.  * virtual timer for threads.
  524.  * SIGALRM (IS POSIX) so some special handling will be
  525.  *  necessary to fake SIGALRM signals
  526.  */
  527. #ifndef SIGINFO
  528. #define SIGINFO 0
  529. #endif
  530. void sig_init(void)
  531. {
  532. static const int signum_to_initialize[] = 
  533.  { SIGCHLD, SIGALRM, SIGVTALRM, SIGINFO, 0 };
  534. static const int signum_to_ignore[] = { SIGKILL, SIGSTOP, 0 };
  535. int i, j;
  536. #if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION)
  537. struct sigaction act;
  538. act.sa_handler = sig_handler_real;
  539. sigemptyset(&(act.sa_mask));
  540. act.sa_flags = 0;
  541. #endif
  542. /* Initialize the important signals */
  543. for (i = 0; signum_to_initialize[i]; i++) {
  544. #if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION)
  545. if (sigaction(signum_to_initialize[i], &act, NULL)) {
  546. #else
  547. if (signal(signum_to_initialize[i], sig_handler_real)) { 
  548. #endif
  549. PANIC();
  550. }
  551. }
  552. /* Initialize the rest of the signals */
  553. for (j = 1; j < SIGMAX; j++) {
  554. for (i = 0; signum_to_initialize[i]; i++) {
  555. if (signum_to_initialize[i] == j) {
  556. goto sig_next;
  557. }
  558. }
  559. /* Because Solaris 2.4 can't deal -- proven */
  560. for (i = 0; signum_to_ignore[i]; i++) {
  561. if (signum_to_ignore[i] == j) {
  562. goto sig_next;
  563. }
  564. }
  565. pthread_signal(j, SIG_DFL);
  566. #if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION)
  567. sigaction(j, &act, NULL);
  568. #else
  569. signal(j, sig_handler_real);
  570. #endif
  571. sig_next:;
  572. }
  573. #if defined BROKEN_SIGNALS 
  574. signal(SIGCHLD, sig_handler_real);
  575. #endif
  576. }