/* Internal version of start_timer that does not protect itself, assuming this has already been done. * Otherwise does as explained above in start_timer. */ STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata) { ABS_TIME at; assert(0 != time_to_expir); sys_get_curr_time(&at); if (first_timeset) { init_timers(); first_timeset = FALSE; } /* We expect no timer with id=<tid> to exist in the timer queue currently. This is asserted in "add_timer" call below. * In pro though, we'll be safe and remove any tids that exist before adding a new entry with the same tid - 2009/10. * If a few years pass without the assert failing, it might be safe then to remove the PRO_ONLY code below. */ # ifndef DEBUG if (timeroot && (timeroot->tid == tid)) sys_canc_timer(); remove_timer(tid); /* Remove timer from chain */ # endif /* Check if # of free timer slots is less than minimum threshold. If so, allocate more of those while it is safe to do so */ if ((GT_TIMER_EXPAND_TRIGGER > num_timers_free) && (1 > timer_stack_count)) gt_timers_alloc(); add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata); /* Link new timer into timer chain */ if ((timeroot->tid == tid) || !timer_active) start_first_timer(&at); }
/* Uninitialize all timers, since we will not be needing them anymore. */ STATICFNDEF void uninit_all_timers(void) { st_timer_alloc *next_timeblk; sys_canc_timer(); first_timeset = TRUE; for (; timer_allocs; timer_allocs = next_timeblk) /* loop over timer_allocs entries and deallocate them */ { next_timeblk = timer_allocs->next; free(timer_allocs->addr); /* free the timeblk */ free((st_timer_alloc *)timer_allocs); /* free the container */ } /* after all timers are removed, we need to set the below pointers to NULL */ timeroot = NULL; timefree = NULL; num_timers_free = 0; /* empty the blockalrm and sigsent entries */ sigemptyset(&blockalrm); sigemptyset(&block_sigsent); sigaction(SIGALRM, &prev_alrm_handler, NULL); timer_active = FALSE; }
/* Cancel timer. * Arguments: tid - timer id */ void cancel_timer(TID tid) { ABS_TIME at; sigset_t savemask; sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */ sys_get_curr_time(&at); if (tid == 0) { assert(process_exiting || IS_GTMSECSHR_IMAGE); /* wcs_phase2_commit_wait relies on this flag being set BEFORE * cancelling all timers. But secshr doesn't have it. */ cancel_all_timers(); uninit_all_timers(); timer_stack_count = 0; sigprocmask(SIG_SETMASK, &savemask, NULL); return; } if (timeroot && (timeroot->tid == tid)) /* if this is the first timer in the chain, stop it */ sys_canc_timer(); remove_timer(tid); /* remove it from the chain */ start_first_timer(&at); /* start the first timer in the chain */ sigprocmask(SIG_SETMASK, &savemask, NULL); }
void generic_signal_handler(int sig, siginfo_t *info, void *context) { gtm_sigcontext_t *context_ptr; void (*signal_routine)(); DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig); /* Save parameter value in global variables for easy access in core */ dont_want_core = FALSE; /* (re)set in case we recurse */ created_core = FALSE; /* we can deal with a second core if needbe */ exi_condition = sig; if (NULL != info) exi_siginfo = *info; else memset(&exi_siginfo, 0, SIZEOF(*info)); # if defined(__ia64) && defined(__hpux) context_ptr = (gtm_sigcontext_t *)context; /* no way to make a copy of the context */ memset(&exi_context, 0, SIZEOF(exi_context)); # else if (NULL != context) exi_context = *(gtm_sigcontext_t *)context; else memset(&exi_context, 0, SIZEOF(exi_context)); context_ptr = &exi_context; # endif /* Check if we are fielding nested immediate shutdown signals */ if (EXIT_IMMED <= exit_state) { switch(sig) { /* If we are dealing with one of these three dangerous signals which we have * already hit while attempting to shutdown once, die with core now. */ case SIGSEGV: case SIGBUS: case SIGILL: if (core_in_progress) { if (exit_handler_active) _exit(sig); else exit(sig); } ++core_in_progress; DUMP_CORE; GTMASSERT; default: ; } } switch(sig) { case SIGTERM: if (!IS_GTMSECSHR_IMAGE) { forced_exit_err = ERR_FORCEDHALT; /* If nothing pending AND we have crit or in wcs_wtstart() or already in exit processing, wait to * invoke shutdown. wcs_wtstart() manipulates the active queue that a concurrent process in crit * in bt_put() might be waiting for. interrupting it can cause deadlocks (see C9C11-002178). */ if (DEFER_EXIT_PROCESSING) { SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ assert(!IS_GTMSECSHR_IMAGE); if (exit_handler_active && !gtm_quiet_halt) SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err); return; } exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; /* Set this BEFORE cancelling timers as wcs_phase2_commit_wait * relies on this. */ if (ERR_FORCEDHALT != forced_exit_err || !gtm_quiet_halt) SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err); } else { /* Special case for gtmsecshr - no deferral just exit */ forced_exit_err = ERR_GTMSECSHRSHUTDN; if (OK_TO_SEND_MSG) send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); } dont_want_core = TRUE; break; case SIGQUIT: /* Handle SIGQUIT specially which we ALWAYS want to defer if possible as it is always sent */ dont_want_core = TRUE; extract_signal_info(sig, &exi_siginfo, context_ptr, &signal_info); switch(signal_info.infotype) { case GTMSIGINFO_NONE: forced_exit_err = ERR_KILLBYSIG; break; case GTMSIGINFO_USER: forced_exit_err = ERR_KILLBYSIGUINFO; break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: forced_exit_err = ERR_KILLBYSIGSINFO1; break; case GTMSIGINFO_ILOC: forced_exit_err = ERR_KILLBYSIGSINFO2; break; case GTMSIGINFO_BADR: forced_exit_err = ERR_KILLBYSIGSINFO3; break; default: exit_state = EXIT_IMMED; GTMASSERT; } /* If nothing pending AND we have crit or already in exit processing, wait to invoke shutdown */ if (DEFER_EXIT_PROCESSING) { SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ assert(!IS_GTMSECSHR_IMAGE); return; } exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; switch(signal_info.infotype) { case GTMSIGINFO_NONE: SEND_AND_PUT_MSG(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); break; case GTMSIGINFO_USER: SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.send_pid, signal_info.send_uid); break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); break; case GTMSIGINFO_ILOC: SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr); break; case GTMSIGINFO_BADR: SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr); break; } break; # ifdef _AIX case SIGDANGER: forced_exit_err = ERR_KRNLKILL; /* If nothing pending AND we have crit or already in exit processing, wait to invoke shutdown */ if (DEFER_EXIT_PROCESSING) { SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ assert(!IS_GTMSECSHR_IMAGE); return; } exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err); dont_want_core = TRUE; break; # endif default: extract_signal_info(sig, &exi_siginfo, context_ptr, &signal_info); switch(signal_info.infotype) { case GTMSIGINFO_NONE: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; SEND_AND_PUT_MSG(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); break; case GTMSIGINFO_USER: /* This signal was SENT to us so it can wait until we are out of crit to cause an exit */ forced_exit_err = ERR_KILLBYSIGUINFO; /* If nothing pending AND we have crit or already exiting, wait to invoke shutdown */ if (DEFER_EXIT_PROCESSING) { assert(!IS_GTMSECSHR_IMAGE); SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ need_core = TRUE; gtm_fork_n_core(); /* Generate "virgin" core while we can */ return; } exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.send_pid, signal_info.send_uid); break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); break; case GTMSIGINFO_ILOC: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr); break; case GTMSIGINFO_BADR: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr); break; default: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; GTMASSERT; } if (0 != signal_info.sig_err) { SEND_AND_PUT_MSG(VARLSTCNT(1) signal_info.sig_err); } break; } /* switch (sig) */ /* Stop the timers but do not cancel them. This allows the timer structures to appear in the core where gtmpcat can * extract them allowing us to see what was going on. */ sys_canc_timer(); FFLUSH(stdout); if (!dont_want_core) { need_core = TRUE; gtm_fork_n_core(); } /* If any special routines are registered to be driven on a signal, drive them now */ if (0 != exi_condition) { /* If this is a GTM-ish process in runtime mode, call the routine to generate the zshow dump. This separate * routine necessary because (1) generic_signal_handler() no longer calls condition handlers and (2) we couldn't * use call_on_signal because it would already be in use in updproc() where it is also possible this routine * needs to be called. Bypass this code if we didn't create a core since that means it is not a GTM * issue that forced its demise (and since this is an uncaring interrupt, we could be in any number of * situations that would cause a ZSHOW dump to explode). Better for user to use jobexam to cause a dump prior * to terminating the process in a deferrable fashion. */ if (!dont_want_core && IS_MCODE_RUNNING && (NULL != (signal_routine = RFPTR(create_fatal_error_zshow_dmp_fptr)))) { /* note assignment of signal_routine above */ SFPTR(create_fatal_error_zshow_dmp_fptr, NULL); (*signal_routine)(exi_condition, FALSE); } /* Some mupip functions define an entry point to drive on signals. Make sure to do this AFTER we create the * dump file above as it may detach things (like the recvpool) we need to create the above dump. */ if (NULL != (signal_routine = call_on_signal)) /* Note assignment */ { call_on_signal = NULL; /* So we don't recursively call ourselves */ (*signal_routine)(); } } if (!IS_GTMSECSHR_IMAGE) { assert((EXIT_IMMED <= exit_state) || !exit_handler_active); exit(-exi_condition); } else return; }