Files
Arquivotheca.SunOS-4.1.4/usr.lib/libsunwindow/notify/ndet_auto.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

218 lines
6.1 KiB
C

#ifndef lint
#ifdef sccs
static char sccsid[] = "@(#)ndet_auto.c 1.1 94/10/31 Copyr 1985 Sun Micro";
#endif
#endif
/*
* Copyright (c) 1985 by Sun Microsystems, Inc.
*/
/*
* Ndet_loop.c - Notification loop.
*/
#include <sys/types.h>
#include <sunwindow/ntfy.h>
#include <sunwindow/ndet.h>
#include <sunwindow/ndis.h> /* For ndis_enqueue */
#include <errno.h>
#include <signal.h>
extern errno;
pkg_private_data u_int ndet_sigs_auto = 0;
pkg_private_data Notify_client ndet_auto_nclient =
(Notify_client)&ndet_sigs_auto;
pkg_private void
ndet_toggle_auto(old_bits, sig)
u_int old_bits;
register int sig;
{
u_int old_bit = old_bits & SIG_BIT(sig);
u_int new_bit = ndet_sigs_auto & SIG_BIT(sig);
if (old_bit && !new_bit)
/* Turn auto signal catcher off for sig */
(void)notify_set_signal_func(ndet_auto_nclient, NOTIFY_FUNC_NULL,
sig, NOTIFY_SYNC);
else if (!old_bit && new_bit)
/* Turn auto signal catcher on for sig */
(void)notify_set_signal_func(ndet_auto_nclient, ndet_auto_sig_func,
sig, NOTIFY_SYNC);
}
/* ARGSUSED */
pkg_private Notify_value
ndet_auto_sig_func(nclient, sig, mode)
Notify_client nclient;
int sig;
Notify_signal_mode mode;
{
return(NOTIFY_DONE);
}
/* ARGSUSED */
pkg_private NTFY_ENUM
ndet_auto_sig_send(client, condition, context)
NTFY_CLIENT *client;
register NTFY_CONDITION *condition;
NTFY_ENUM_DATA context;
{
NTFY_ENUM ndet_auto_sigchld(), ndet_auto_sigterm();
register NDET_ENUM_SEND *enum_send = (NDET_ENUM_SEND *)context;
ntfy_assert(condition->type == NTFY_SYNC_SIGNAL, "Auto sig is async");
/* Sweep all conditions & send notifications (recursive enumeration) */
switch (condition->data.signal) {
case SIGIO:
case SIGURG: {
NDET_ENUM_SEND enum_send2;
register int loop_limiter = 0;
fd_set ibits, obits, ebits, tfd;
int nfds;
/* Remember who was already notified (block copy get *bits) */
enum_send2 = *enum_send;
while (loop_limiter++ < 5) {
FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&ebits);
if (condition->data.signal == SIGIO)
ibits = obits = ndet_fasync_mask;
else
ebits = ndet_fasync_mask;
/* Do a select to see who needs service */
nfds = notify_select(FD_SETSIZE,
&ibits, &obits, &ebits, &ndet_polling_tv);
/* See if select returned unconventionally */
if (nfds == -1) {
/* Note: *bits are undefined here */
switch (errno) {
case EINTR:
/* Signals received so try again */
continue;
case EBADF:
ntfy_fatal_error("2ndary select EBADF");
return(NTFY_ENUM_NEXT);
default:
ntfy_fatal_error("2ndary select error");
return(NTFY_ENUM_NEXT);
}
}
/*
* Modify secondary enumeration record to be those
* selected but not already notified.
*/
/*
enum_send2.ibits = (ibits ^ enum_send2.ibits) & ibits;
enum_send2.obits = (obits ^ enum_send2.obits) & obits;
enum_send2.ebits = (ebits ^ enum_send2.ebits) & ebits;
*/
(void)ntfy_fd_cpy_xor(&enum_send2.ibits, &ibits);
(void)ntfy_fd_cpy_and(&enum_send2.ibits, &ibits);
(void)ntfy_fd_cpy_xor(&enum_send2.obits, &obits);
(void)ntfy_fd_cpy_and(&enum_send2.obits, &obits);
(void)ntfy_fd_cpy_xor(&enum_send2.ebits, &ebits);
(void)ntfy_fd_cpy_and(&enum_send2.ebits, &ebits);
/* Send notifications */
if (ntfy_fd_anyset(&enum_send2.ibits) ||
ntfy_fd_anyset(&enum_send2.obits) ||
ntfy_fd_anyset(&enum_send2.ebits))
(void) ntfy_enum_conditions(ndet_clients,
ndet_fd_send, (NTFY_ENUM_DATA)&enum_send2);
/*
* Update those who have been notified
* (Note: tidy, but is this required?)
*/
(void)ntfy_fd_cpy_or(&enum_send->ibits, &enum_send2.ibits);
(void)ntfy_fd_cpy_or(&enum_send->obits, &enum_send2.obits);
(void)ntfy_fd_cpy_or(&enum_send->ebits, &enum_send2.ebits);
break;
}
break;
}
case SIGCHLD: {
NTFY_WAIT3_DATA wd;
NTFY_ENUM ndet_wait_send();
enum_send->wait3 = &wd;
/* Look for as many children as have changed state */
while ((wd.pid = wait3(&wd.status, WNOHANG | WUNTRACED,
&wd.rusage)) > 0)
(void) ntfy_enum_conditions(ndet_clients,
ndet_auto_sigchld, context);
break;
}
case SIGTERM:
/* Terminate the notifier */
(void) notify_stop();
/* Set up to exit(1) after dispatch all notifications */
ndet_flags |= NDET_EXIT_SOON;
return(NTFY_ENUM_TERM);
case SIGALRM:
ndet_update_real_itimer();
break;
case SIGVTALRM:
ndet_update_virtual_itimer();
break;
default:
ntfy_fatal_error("Nclient unprepared to handle signal");
break;
}
return(NTFY_ENUM_NEXT);
}
/*
* Enqueue wait3 notification if the waited for pid matches the pid that
* the notifier has noticed changing state.
*/
pkg_private NTFY_ENUM
ndet_auto_sigchld(client, condition, context)
NTFY_CLIENT *client;
register NTFY_CONDITION *condition;
NTFY_ENUM_DATA context;
{
register NDET_ENUM_SEND *enum_send = (NDET_ENUM_SEND *)context;
NTFY_CLIENT client_tmp;
NTFY_CONDITION condition_tmp;
NTFY_WAIT3_DATA wait3_tmp;
Notify_func functions[NTFY_FUNCS_MAX];
if (condition->type == NTFY_WAIT3 &&
condition->data.pid == enum_send->wait3->pid) {
/*
* Remember contents of following for call to ndis_enqueue
* because call to notify_set_wait3_func can invalidate.
*/
client_tmp = *client;
condition_tmp = *condition;
wait3_tmp = *enum_send->wait3;
condition_tmp.data.wait3 = &wait3_tmp;
if (condition->func_count > 1) {
condition_tmp.callout.functions = functions;
bcopy((caddr_t)condition->callout.functions,
(caddr_t)condition_tmp.callout.functions,
sizeof(NTFY_NODE));
} else
condition_tmp.callout.function =
condition->callout.function;
/* Remove conditon if child process exited/killed */
if (WIFEXITED(enum_send->wait3->status) ||
WIFSIGNALED(enum_send->wait3->status)) {
/*
* Enumerator (which is calling this) is designed to
* survive having condition disappear in middle of
* enumeration.
*/
(void)notify_set_wait3_func(client->nclient,
NOTIFY_FUNC_NULL, condition->data.pid);
}
/* Dispatch notification */
if (ndis_enqueue(&client_tmp, &condition_tmp) != NOTIFY_OK)
ntfy_fatal_error("Error when enq condition");
}
return(NTFY_ENUM_NEXT);
}