📄 ndet_loop.c
字号:
#ifndef lint#ifdef sccsstatic char sccsid[] = "@(#)ndet_loop.c 1.1 92/07/30 Copyr 1985 Sun Micro";#endif#endif/* * Copyright (c) 1985 by Sun Microsystems, Inc. *//* * Ndet_loop.c - Notification loop. */#include <sunwindow/ntfy.h>#include <sunwindow/ndet.h>#include <sunwindow/nint.h>#include <sunwindow/ndis.h> /* For ndis_dispatch */#include <syscall.h>#include <errno.h>#include <signal.h>#include <stdio.h> /* For temp debugging */extern int errno;pkg_private_data u_int ndet_flags = 0;pkg_private_data NTFY_CLIENT *ndet_clients = 0;pkg_private_data NTFY_CLIENT *ndet_client_latest = 0;pkg_private_data u_int ndet_sigs_received = 0;pkg_private_data u_int ndet_sigs_managing = 0;pkg_private_data fd_set ndet_fasync_mask = 0; /* Initialized to 0 by the compiler*/pkg_private_data fd_set ndet_fndelay_mask = 0; /* Maintained, but really used? */pkg_private_data struct timeval ndet_polling_tv = {0,0};pkg_private_data fd_set ndet_ibits = 0, ndet_obits = 0, ndet_ebits = 0; /* = 0; */static struct timeval ndet_signal_check; /* Minimum select timeout */pkg_private_data struct sigvec ndet_prev_sigvec[NSIG] = 0;pkg_private void ndet_signal_catcher();pkg_private_data struct sigvec ndet_sigvec = {ndet_signal_catcher, 0, 0};static int ndet_signal_code;static struct sigcontext *ndet_signal_context;static void ndet_update_itimer();static void ndet_send_async_sigs();static void ndet_fig_fd_change(), ndet_fig_wait3_change(), ndet_fig_destroy_change(), ndet_fig_sig_change();static NTFY_ENUM ndet_sig_send(), ndet_poll_send();static NTFY_ENUM ndet_itimer_change();static NTFY_ENUM ndet_destroy_change();static NTFY_ENUM ndet_sig_change();static NTFY_ENUM ndet_fd_change();static NTFY_ENUM ndet_wait3_change();static NTFY_ENUM ndet_virtual_set_tv_update();static NTFY_ENUM ndet_async_sig_send();#ifdef lint/* VARARGS *//* ARGSUSED */int syscall(a) { return(0);} /* When syscall put in llib-lc then remove */#endif lintextern Notify_errornotify_start(){ register struct timeval *timer; fd_set ibits, obits, ebits; register int nfds; NDET_ENUM_SEND enum_send; int errno_remember = errno; Notify_error return_code; FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&ebits); /* Notify_start is not reentrant */ if (ndet_flags & NDET_STARTED) { ntfy_set_errno(NOTIFY_INVAL); return(notify_errno); } /* Always go around the loop at least once */ ndet_flags |= NDET_STARTED; do { NTFY_BEGIN_CRITICAL; /* Ndet_update_*_itimer (below) may set up NDET_ITIMER_ENQ*/ ndet_flags &= ~NDET_ITIMER_ENQ; /* If nothing has changed then do no set up */ if (ndet_flags & NDET_CONDITION_CHANGE) { if (ndet_flags & NDET_REAL_CHANGE) ndet_update_real_itimer(); if (ndet_flags & NDET_VIRTUAL_CHANGE) ndet_update_virtual_itimer(); if (ndet_flags & NDET_FD_CHANGE) ndet_fig_fd_change(); if (ndet_flags & NDET_WAIT3_CHANGE) ndet_fig_wait3_change(); if (ndet_flags & NDET_DESTROY_CHANGE) ndet_fig_destroy_change(); /* * Always handle signal changes last because other * ndet_*_change and ndet_update_*_itimer calls may * have set NDET_SIGNAL_CHANGE in ndet_flags. */ if (ndet_flags & NDET_SIGNAL_CHANGE) ndet_fig_sig_change(); } /* * Set up select parameters. Wouldn't get changes from * signal processing this time around. Poll if stuff in * the dispatch queue. */ timer = ( ndet_flags & (NDET_POLL | NDET_ITIMER_ENQ | NDET_NO_DELAY) || ndis_clients != NTFY_CLIENT_NULL)? &ndet_polling_tv: NTFY_TIMEVAL_NULL; ibits = ndet_ibits; obits = ndet_obits; ebits = ndet_ebits; NTFY_END_CRITICAL; /* * From the tests of ndet_sigs_received until get into * pause or select below is a race condition. * It is possible to get a signal during this time that wouldn't * get serviced until something breaks us out of the block. * Can't get away from this. UNIX needs a version of select * and pause that will simultaneously release blocked signals. * We test ndet_sigs_received as late as possible in order * to reduce this window of vulnerability. */ if (!ntfy_fd_anyset(&ibits) && !ntfy_fd_anyset(&obits) && !ntfy_fd_anyset(&ebits) && timer == NTFY_TIMEVAL_NULL && !ndet_sigs_received) { if (ndet_sigs_managing != 0) { /* Wait for interrupt */ pause(); } else { /* Not detecting ANY conditions */ return_code = NOTIFY_NO_CONDITION; goto Finish; } } else { /* * Hack to avoid race condition described below. * notify_signal_check must be called explicitly * to enable this mechanism. */ if ((timer == NTFY_TIMEVAL_NULL) && (timerisset(&ndet_signal_check))) timer = &ndet_signal_check; /* * Wait for select to return. * * Do this ndet_sigs_received test at the last possible * nano in order to reduce the unavoidable race * condition between detecting signal arrival and * making the call to select (which will return with an * EINTR when a signal arrives while IN select, * not ON THE WAY into select). */ nfds = syscall(SYS_select, FD_SETSIZE, &ibits, &obits, &ebits, (ndet_sigs_received)? &ndet_polling_tv: timer); errno_remember = errno; /* See if select returned unconventionally */ if (nfds == -1) { /* Clear *bits when in an undefined situation */ FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&ebits); switch (errno) { case EINTR: /* Signals received */ if (ndet_flags & NDET_STOP_ON_SIG) (void) notify_stop(); break; /* Out of switch */ case EBADF: ntfy_set_errno(NOTIFY_BADF); goto Error; default: ntfy_set_errno(NOTIFY_INVAL); goto Error; } } else { /* * Terminate notification loop if ask to * stop on sig and received signal before * entering select. */ if (ndet_flags & NDET_STOP_ON_SIG && ndet_sigs_received) { (void) notify_stop(); /* * Modify errno to indicate that an * signal was received during select. */ errno_remember = errno = EINTR; } /* * (timer && (nfds == 0)) means select timer expired. * Since will only go off in polling situation and * we send poll notifications every time around loop, * fall through. */ } } /* Enqueue detected notifications with the dispatcher */ NTFY_BEGIN_CRITICAL; /* Set up enumeration record */ enum_send.ibits = ibits; enum_send.obits = obits; enum_send.ebits = ebits; enum_send.wait3 = NTFY_WAIT3_DATA_NULL; timerclear(&(enum_send.current_tv)); enum_send.sigs = ndet_sigs_received; ndet_sigs_received = 0; /* Check for fd related condition */ /*if (ibits || obits || ebits) */ if (ntfy_fd_anyset(&ibits) || ntfy_fd_anyset(&obits) || ntfy_fd_anyset(&ebits)) if (ntfy_enum_conditions(ndet_clients, ndet_fd_send, (NTFY_ENUM_DATA)&enum_send) == NTFY_ENUM_TERM) goto Protected_Error; /* Check for signal related condition */ if (enum_send.sigs) /* * Use paranoid enum because when get in to * ndet_auto_sig_send will do another enumeration * that can axe client/condition but not have the * opportunity to return NTFY_ENUM_SKIP to the * original enumeration (this one). */ if(ntfy_paranoid_enum_conditions(ndet_clients, ndet_sig_send, (NTFY_ENUM_DATA)&enum_send) == NTFY_ENUM_TERM) goto Protected_Error; if (ndet_flags & NDET_POLL) if (ntfy_enum_conditions(ndet_clients, ndet_poll_send, NTFY_ENUM_DATA_NULL) == NTFY_ENUM_TERM) goto Protected_Error; NTFY_END_CRITICAL; /* Dispatch any notification enqueued with the dispatcher */ if (ndis_dispatch() != NOTIFY_OK) goto Error; } while (!(ndet_flags & (NDET_STOP | NDET_NO_DELAY))); return_code = NOTIFY_OK; goto Finish;Protected_Error: NTFY_END_CRITICAL;Error: return_code = notify_errno;Finish: ndet_flags &= ~(NDET_STOP | NDET_STARTED); if (ndet_flags & NDET_EXIT_SOON) { /* Allow everyone to clean up */ (void) notify_die(DESTROY_PROCESS_DEATH); exit(1); } if (ndet_flags & NDET_STOP_ON_SIG) {#ifdef NTFY_DEBUG_SELECT char sb[100]; sprintf(sb, "errno changed (old=%ld, cur=%ld); reset to old", errno_remember, errno); ntfy_assert(errno == errno_remember, sb);#endif NTFY_DEBUG_SELECT errno = errno_remember; } return(return_code);}/* * Set flag indicating that should return from notify_start. */extern Notify_errornotify_stop(){ if (ndet_flags & NDET_STARTED) { ndet_flags |= NDET_STOP; return(NOTIFY_OK); } else return(NOTIFY_NOT_STARTED);}/* * Some fd related condition has changed. Reset all ndet_*bits. * Enable(disable) notifier auto signal catching of SIGIO and SIGURG. */static voidndet_fig_fd_change(){ u_int sigs_tmp; ndet_flags &= ~NDET_FD_CHANGE; /* Remember bits of notifier auto signal catcher */ sigs_tmp = ndet_sigs_auto; /* Zero out bits */ FD_ZERO(&ndet_ibits); FD_ZERO(&ndet_obits); FD_ZERO(&ndet_ebits); ndet_sigs_auto &= ~(SIG_BIT(SIGIO) | SIG_BIT(SIGURG)); /* Recompute all bits */ (void) ntfy_enum_conditions(ndet_clients, ndet_fd_change, NTFY_ENUM_DATA_NULL); /* Toggle notifier auto signal catching if situation changed */ ndet_toggle_auto(sigs_tmp, SIGIO); ndet_toggle_auto(sigs_tmp, SIGURG);}/* ARGSUSED */static NTFY_ENUMndet_fd_change(client, condition, context) NTFY_CLIENT *client; NTFY_CONDITION *condition; NTFY_ENUM_DATA context;{ switch (condition->type) { case NTFY_INPUT: if (FD_ISSET(condition->data.fd, &ndet_fasync_mask)) ndet_sigs_auto |= SIG_BIT(SIGIO); else /*ndet_ibits |= bit; */ FD_SET(condition->data.fd, &ndet_ibits); break; case NTFY_OUTPUT: if (FD_ISSET(condition->data.fd, &ndet_fasync_mask)) ndet_sigs_auto |= SIG_BIT(SIGIO); else /*ndet_obits |= bit; */ FD_SET(condition->data.fd, &ndet_obits); break; case NTFY_EXCEPTION: if (FD_ISSET(condition->data.fd, &ndet_fasync_mask)) ndet_sigs_auto |= SIG_BIT(SIGURG); else /*ndet_ebits |= bit; */ FD_SET(condition->data.fd, &ndet_ebits); break; default: {} } return(NTFY_ENUM_NEXT);}/* * Some wait3 condition has changed. * Enable(disable) notifier auto signal catching of SIGCHLD. */static voidndet_fig_wait3_change(){ u_int sigs_tmp; ndet_flags &= ~NDET_WAIT3_CHANGE; /* Remember bits of notifier auto signal catcher */ sigs_tmp = ndet_sigs_auto; /* Zero out bits */ ndet_sigs_auto &= ~SIG_BIT(SIGCHLD); /* See if any wait conditions */ (void) ntfy_enum_conditions(ndet_clients, ndet_wait3_change, NTFY_ENUM_DATA_NULL); /* Toggle notifier auto signal catching if situation changed */ ndet_toggle_auto(sigs_tmp, SIGCHLD);}/* ARGSUSED */static NTFY_ENUMndet_wait3_change(client, condition, context) NTFY_CLIENT *client; NTFY_CONDITION *condition; NTFY_ENUM_DATA context;{ if (condition->type == NTFY_WAIT3) ndet_sigs_auto |= SIG_BIT(SIGCHLD); return(NTFY_ENUM_NEXT);}/* * Some virtual itimer related condition has changed. Update all virtual * itimers. Determine minimum wait and set virtual itimer. * Enable(disable) notifier auto signal catching of SIGVTALRM. */pkg_private voidndet_update_virtual_itimer(){ struct timeval ndet_virtual_min(); struct itimerval current_itimer; NDET_ENUM_ITIMER enum_itimer; int n; ndet_flags &= ~(NDET_VIRTUAL_CHANGE | NDET_VIRTUAL_POLL); /* Initialize virtual itimer update probe */ enum_itimer.type = NTFY_VIRTUAL_ITIMER; enum_itimer.polling_bit = NDET_VIRTUAL_POLL; enum_itimer.signal = SIGVTALRM; enum_itimer.which = ITIMER_VIRTUAL; enum_itimer.min_func = ndet_virtual_min; /* Virtual itimers are relative to current state of process itimer */ n = getitimer(ITIMER_VIRTUAL, ¤t_itimer); /* SYSTEM CALL */ ntfy_assert(n == 0, "Unexpected error: getitimer"); enum_itimer.current_tv = current_itimer.it_value; /* enum_itimer.min_tv is initialized in ndet_update_itimer. */ /* * Update existing virtual itimer conditions and find what process * itimer was set to. */ ndet_update_itimer(&enum_itimer); /* Update set_tv in existing virtual itimers */ (void) ntfy_enum_conditions(ndet_clients, ndet_virtual_set_tv_update, (NTFY_ENUM_DATA)&enum_itimer.min_tv);}/* * Some real itimer related condition has changed. * Determine minimum wait and set real itimer. * Enable(disable) notifier auto signal catching of SIGALRM. */pkg_private voidndet_update_real_itimer(){ struct timeval ndet_real_min(); NDET_ENUM_ITIMER enum_itimer; int n; ndet_flags &= ~(NDET_REAL_CHANGE | NDET_REAL_POLL); /* Initialize virtual itimer update probe */ enum_itimer.type = NTFY_REAL_ITIMER; enum_itimer.polling_bit = NDET_REAL_POLL; enum_itimer.signal = SIGALRM; enum_itimer.which = ITIMER_REAL; enum_itimer.min_func = ndet_real_min; /* Real itimers are relative to current time of day */ n = gettimeofday(&enum_itimer.current_tv, (struct timezone *)0); /* SYSTEM CALL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -