diff --git a/etc/system.conf b/etc/system.conf index 1edd43d0d..e03d21393 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -60,7 +60,6 @@ service pm FORK # 01 EXEC_NEWMEM # 03 WILLEXIT # 05 - NOTIFY_SIG # 39 GETRUSAGE # 47 ; io NONE; # No I/O range allowed diff --git a/minix/commands/service/parse.c b/minix/commands/service/parse.c index 593c2ae75..af2d349ef 100644 --- a/minix/commands/service/parse.c +++ b/minix/commands/service/parse.c @@ -741,9 +741,6 @@ struct { "GETPHYS", VM_GETPHYS }, { "GETREF", VM_GETREF }, { "RS_SET_PRIV", VM_RS_SET_PRIV }, - { "QUERY_EXIT", VM_QUERY_EXIT }, - { "WATCH_EXIT", VM_WATCH_EXIT }, - { "NOTIFY_SIG", VM_NOTIFY_SIG }, { "INFO", VM_INFO }, { "RS_UPDATE", VM_RS_UPDATE }, { "RS_MEMCTL", VM_RS_MEMCTL }, diff --git a/minix/include/minix/callnr.h b/minix/include/minix/callnr.h index 7f5f36d26..46b91a825 100644 --- a/minix/include/minix/callnr.h +++ b/minix/include/minix/callnr.h @@ -50,7 +50,7 @@ #define PM_REBOOT (PM_BASE + 37) #define PM_SVRCTL (PM_BASE + 38) #define PM_SPROF (PM_BASE + 39) -/* PM call number 40 is currently unused. */ +#define PM_PROCEVENTMASK (PM_BASE + 40) #define PM_SRV_FORK (PM_BASE + 41) #define PM_SRV_KILL (PM_BASE + 42) #define PM_EXEC_NEW (PM_BASE + 43) diff --git a/minix/include/minix/com.h b/minix/include/minix/com.h index 4f611224e..9fcb12552 100644 --- a/minix/include/minix/com.h +++ b/minix/include/minix/com.h @@ -593,6 +593,7 @@ *===========================================================================*/ #define COMMON_RQ_BASE 0xE00 +#define COMMON_RS_BASE 0xE80 /* Field names for system signals (sent by a signal manager). */ #define SIGS_SIGNAL_RECEIVED (COMMON_RQ_BASE+0) @@ -603,6 +604,12 @@ /* Common fault injection ctl request to all processes. */ #define COMMON_REQ_FI_CTL (COMMON_RQ_BASE+2) +/* Process event message from PM. */ +#define PROC_EVENT (COMMON_RQ_BASE+3) + +/* Reply to process event message to PM. */ +#define PROC_EVENT_REPLY (COMMON_RS_BASE+0) + /*===========================================================================* * Messages for VM server * *===========================================================================*/ @@ -708,12 +715,6 @@ # define VM_RS_BUF m2_l1 # define VM_RS_SYS m2_i2 -#define VM_QUERY_EXIT (VM_RQ_BASE+38) - -#define VM_NOTIFY_SIG (VM_RQ_BASE+39) -# define VM_NOTIFY_SIG_ENDPOINT m1_i1 -# define VM_NOTIFY_SIG_IPC m1_i2 - #define VM_INFO (VM_RQ_BASE+40) /* VM_INFO 'what' values. */ @@ -734,8 +735,6 @@ # define VM_RS_CTL_ADDR m2_p1 # define VM_RS_CTL_LEN m2_i3 -#define VM_WATCH_EXIT (VM_RQ_BASE+43) - #define VM_REMAP_RO (VM_RQ_BASE+44) /* same args as VM_REMAP */ diff --git a/minix/include/minix/ipc.h b/minix/include/minix/ipc.h index b4c18b7e0..00e25add8 100644 --- a/minix/include/minix/ipc.h +++ b/minix/include/minix/ipc.h @@ -1273,6 +1273,13 @@ typedef struct { } mess_lsys_pm_getprocnr; _ASSERT_MSG_SIZE(mess_lsys_pm_getprocnr); +typedef struct { + unsigned int mask; + + uint8_t padding[52]; +} mess_lsys_pm_proceventmask; +_ASSERT_MSG_SIZE(mess_lsys_pm_proceventmask); + typedef struct { uid_t uid; gid_t gid; @@ -1361,13 +1368,6 @@ typedef struct { } mess_lsys_vm_map_phys; _ASSERT_MSG_SIZE(mess_lsys_vm_map_phys); -typedef struct { - endpoint_t ret_pt; - int is_more; - uint8_t padding[48]; -} mess_lsys_vm_query_exit; -_ASSERT_MSG_SIZE(mess_lsys_vm_query_exit); - typedef struct { endpoint_t endpt; vir_bytes addr; @@ -1403,12 +1403,6 @@ typedef struct { } mess_lsys_vm_vmremap; _ASSERT_MSG_SIZE(mess_lsys_vm_vmremap); -typedef struct { - endpoint_t ep; - uint8_t padding[52]; -} mess_lsys_vm_watch_exit; -_ASSERT_MSG_SIZE(mess_lsys_vm_watch_exit); - typedef struct { size_t oldlen; uint8_t padding[52]; @@ -1564,6 +1558,14 @@ typedef struct { } mess_pm_lsys_getprocnr; _ASSERT_MSG_SIZE(mess_pm_lsys_getprocnr); +typedef struct { + endpoint_t endpt; + unsigned int event; + + uint8_t padding[48]; +} mess_pm_lsys_proc_event; +_ASSERT_MSG_SIZE(mess_pm_lsys_proc_event); + typedef struct { int num; @@ -2186,6 +2188,7 @@ typedef struct noxfer_message { mess_lsys_pci_busc_get_bar m_lsys_pci_busc_get_bar; mess_lsys_pm_getepinfo m_lsys_pm_getepinfo; mess_lsys_pm_getprocnr m_lsys_pm_getprocnr; + mess_lsys_pm_proceventmask m_lsys_pm_proceventmask; mess_lsys_pm_srv_fork m_lsys_pm_srv_fork; mess_lsys_sched_scheduling_start m_lsys_sched_scheduling_start; mess_lsys_sched_scheduling_stop m_lsys_sched_scheduling_stop; @@ -2196,12 +2199,10 @@ typedef struct noxfer_message { mess_lsys_vm_getref m_lsys_vm_getref; mess_lsys_vm_info m_lsys_vm_info; mess_lsys_vm_map_phys m_lsys_vm_map_phys; - mess_lsys_vm_query_exit m_lsys_vm_query_exit; mess_lsys_vm_rusage m_lsys_vm_rusage; mess_lsys_vm_unmap_phys m_lsys_vm_unmap_phys; mess_lsys_vm_update m_lsys_vm_update; mess_lsys_vm_vmremap m_lsys_vm_vmremap; - mess_lsys_vm_watch_exit m_lsys_vm_watch_exit; mess_mib_lc_sysctl m_mib_lc_sysctl; mess_mmap m_mmap; mess_net_netdrv_dl_conf m_net_netdrv_dl_conf; @@ -2222,6 +2223,7 @@ typedef struct noxfer_message { mess_pm_lexec_exec_new m_pm_lexec_exec_new; mess_pm_lsys_getepinfo m_pm_lsys_getepinfo; mess_pm_lsys_getprocnr m_pm_lsys_getprocnr; + mess_pm_lsys_proc_event m_pm_lsys_proc_event; mess_pm_lsys_sigs_signal m_pm_lsys_sigs_signal; mess_pm_sched_scheduling_set_nice m_pm_sched_scheduling_set_nice; mess_pty_ptyfs_req m_pty_ptyfs_req; diff --git a/minix/include/minix/syslib.h b/minix/include/minix/syslib.h index c0de856f5..45b923649 100644 --- a/minix/include/minix/syslib.h +++ b/minix/include/minix/syslib.h @@ -276,5 +276,13 @@ int copyfd(endpoint_t endpt, int fd, int what); #define COPYFD_TO 1 /* copy file descriptor to remote process */ #define COPYFD_CLOSE 2 /* close file descriptor in remote process */ +/* + * These are also the event numbers used in PROC_EVENT messages, but in order + * to allow for subscriptions to multiple events, they form a bit mask. + */ +#define PROC_EVENT_EXIT 0x01 /* process has exited */ +#define PROC_EVENT_SIGNAL 0x02 /* process has caught signal */ +int proceventmask(unsigned int mask); + #endif /* _SYSLIB_H */ diff --git a/minix/include/minix/vm.h b/minix/include/minix/vm.h index c8af1b3f8..88420ddbb 100644 --- a/minix/include/minix/vm.h +++ b/minix/include/minix/vm.h @@ -16,13 +16,10 @@ int vm_getdma(endpoint_t *procp, phys_bytes *basep, phys_bytes *sizep); void *vm_map_phys(endpoint_t who, void *physaddr, size_t len); int vm_unmap_phys(endpoint_t who, void *vaddr, size_t len); -int vm_notify_sig(endpoint_t ep, endpoint_t ipc_ep); int vm_set_priv(endpoint_t ep, void *buf, int sys_proc); int vm_update(endpoint_t src_e, endpoint_t dst_e, int flags); int vm_memctl(endpoint_t ep, int req, void** addr, size_t *len); int vm_prepare(endpoint_t src_e, endpoint_t dst_e, int flags); -int vm_query_exit(endpoint_t *endpt); -int vm_watch_exit(endpoint_t ep); int minix_vfs_mmap(endpoint_t who, off_t offset, size_t len, dev_t dev, ino_t ino, int fd, u32_t vaddr, u16_t clearend, u16_t flags); diff --git a/minix/lib/libsys/Makefile b/minix/lib/libsys/Makefile index 30ce1a845..d19fbe140 100644 --- a/minix/lib/libsys/Makefile +++ b/minix/lib/libsys/Makefile @@ -35,6 +35,7 @@ SRCS+= \ mapdriver.c \ optset.c \ panic.c \ + proceventmask.c \ safecopies.c \ sched_start.c \ sched_stop.c \ @@ -99,10 +100,8 @@ SRCS+= \ vm_info.c \ vm_map_phys.c \ vm_memctl.c \ - vm_notify_sig.c \ vm_prepare.c \ vm_procctl.c \ - vm_query_exit.c \ vm_set_priv.c \ vm_update.c diff --git a/minix/lib/libsys/proceventmask.c b/minix/lib/libsys/proceventmask.c new file mode 100644 index 000000000..984a3d73e --- /dev/null +++ b/minix/lib/libsys/proceventmask.c @@ -0,0 +1,20 @@ +#include "syslib.h" + +#include + +/* + * Subscribe to a certain set of process events from PM. Subsequent calls will + * replace the set, and the empty set (a zero mask) will unsubscribe the caller + * altogether. Usage restrictions apply; see PM's event.c for details. Return + * OK or a negative error code. + */ +int +proceventmask(unsigned int mask) +{ + message m; + + memset(&m, 0, sizeof(m)); + m.m_lsys_pm_proceventmask.mask = mask; + + return _taskcall(PM_PROC_NR, PM_PROCEVENTMASK, &m); +} diff --git a/minix/lib/libsys/vm_notify_sig.c b/minix/lib/libsys/vm_notify_sig.c deleted file mode 100644 index cf631fa69..000000000 --- a/minix/lib/libsys/vm_notify_sig.c +++ /dev/null @@ -1,22 +0,0 @@ - -#include "syslib.h" - -#include -#include - -/*===========================================================================* - * vm_notify_sig * - *===========================================================================*/ -int vm_notify_sig(endpoint_t ep, endpoint_t ipc_ep) -{ - message m; - int result; - - memset(&m, 0, sizeof(m)); - m.VM_NOTIFY_SIG_ENDPOINT = ep; - m.VM_NOTIFY_SIG_IPC = ipc_ep; - - result = _taskcall(VM_PROC_NR, VM_NOTIFY_SIG, &m); - return(result); -} - diff --git a/minix/lib/libsys/vm_query_exit.c b/minix/lib/libsys/vm_query_exit.c deleted file mode 100644 index 6d8ca33ef..000000000 --- a/minix/lib/libsys/vm_query_exit.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "syslib.h" -#include -#include - -/* - * Return a negative error code if the query itself or the processing of the - * query resulted in an error. - * Return 1 if there are more processes waiting to be queried. - * Return 0 if there are no more processes. - * Note that for the return value of 0 and 1, the 'endpt' is set accordingly. - */ -int -vm_query_exit(int *endpt) -{ - message m; - int r; - - memset(&m, 0, sizeof(m)); - r = _taskcall(VM_PROC_NR, VM_QUERY_EXIT, &m); - if (r != OK) - return r; - if (endpt == NULL) - return EFAULT; - - *endpt = m.m_lsys_vm_query_exit.ret_pt; - return (m.m_lsys_vm_query_exit.is_more ? 1 : 0); -} - -int -vm_watch_exit(endpoint_t ep) -{ - message m; - - memset(&m, 0, sizeof(m)); - m.m_lsys_vm_watch_exit.ep = ep; - return _taskcall(VM_PROC_NR, VM_WATCH_EXIT, &m); -} diff --git a/minix/servers/ipc/inc.h b/minix/servers/ipc/inc.h index d9728467f..dde504393 100644 --- a/minix/servers/ipc/inc.h +++ b/minix/servers/ipc/inc.h @@ -52,7 +52,7 @@ int do_semget(message *); int do_semctl(message *); int do_semop(message *); int is_sem_nil(void); -void sem_process_vm_notify(void); +void sem_process_event(endpoint_t, int); /* utility.c */ int check_perm(struct ipc_perm *, endpoint_t, int); diff --git a/minix/servers/ipc/ipc.conf b/minix/servers/ipc/ipc.conf index e2300e6bb..8fb8b4aa3 100644 --- a/minix/servers/ipc/ipc.conf +++ b/minix/servers/ipc/ipc.conf @@ -14,7 +14,5 @@ service ipc SHM_UNMAP GETPHYS GETREF - QUERY_EXIT - WATCH_EXIT ; }; diff --git a/minix/servers/ipc/main.c b/minix/servers/ipc/main.c index 948b72b27..8dd3a1e36 100644 --- a/minix/servers/ipc/main.c +++ b/minix/servers/ipc/main.c @@ -23,6 +23,18 @@ static int sef_cb_init_fresh(int type __unused, sef_init_info_t * info __unused) { + /* + * Subscribe to PM process events. While it might be tempting to + * implement a system that subscribes to events only from processes + * that are actually blocked (or using the SysV IPC facilities at all), + * this would result in race conditions where subscription could happen + * "too late" for an ongoing signal delivery, causing the affected + * process to deadlock. By issuing this one blocking subscription call + * at startup, we eliminate all possibilities of such race conditions, + * at the cost of receiving notifications for literally all processes. + */ + proceventmask(PROC_EVENT_EXIT | PROC_EVENT_SIGNAL); + return OK; } @@ -78,19 +90,24 @@ main(int argc, char ** argv) printf("IPC: got %d from %d\n", m.m_type, m.m_source); if (is_ipc_notify(ipc_status)) { - switch (m.m_source) { - case VM_PROC_NR: - /* - * Currently, only semaphore handling needs - * to know about processes exiting. - */ - sem_process_vm_notify(); - break; - default: - printf("IPC: ignoring notification from %d\n", - m.m_source); - break; - } + printf("IPC: ignoring notification from %d\n", + m.m_source); + continue; + } + + if (m.m_source == PM_PROC_NR && m.m_type == PROC_EVENT) { + /* + * Currently, only semaphore handling needs to know + * about processes being signaled and exiting. + */ + sem_process_event(m.m_pm_lsys_proc_event.endpt, + m.m_pm_lsys_proc_event.event == PROC_EVENT_EXIT); + + /* Echo the request as a reply back to PM. */ + m.m_type = PROC_EVENT_REPLY; + if ((r = asynsend3(m.m_source, &m, AMF_NOREPLY)) != OK) + printf("IPC: replying to PM process event " + "failed (%d)\n", r); continue; } @@ -99,16 +116,6 @@ main(int argc, char ** argv) if (call_index < __arraycount(call_vec) && call_vec[call_index] != NULL) { - /* - * If any process does an IPC call, we have to know - * about it exiting. Tell VM to watch it for us. - * TODO: this is not true; limit to affected processes. - */ - if (vm_watch_exit(m.m_source) != OK) { - printf("IPC: watch failed on %d\n", - m.m_source); - } - r = call_vec[call_index](&m); } else r = ENOSYS; diff --git a/minix/servers/ipc/sem.c b/minix/servers/ipc/sem.c index 88bea83a7..8e4fc82e8 100644 --- a/minix/servers/ipc/sem.c +++ b/minix/servers/ipc/sem.c @@ -637,19 +637,18 @@ is_sem_nil(void) return (sem_list_nr == 0); } +/* + * Check whether processes have terminated and/or are about to have a signal + * caught, in which case any pending blocking operation must be cancelled. + */ void -sem_process_vm_notify(void) +sem_process_event(endpoint_t endpt, int has_exited __unused) { - endpoint_t endpt; - int r; - /* For each endpoint, check whether it is waiting. */ - while ((r = vm_query_exit(&endpt)) >= 0) { - remove_process(endpt); - - if (r == 0) - break; - } - if (r < 0) - printf("IPC: query exit error (%d)\n", r); + /* + * As long as we do not support SEM_UNDO, it does not matter whether + * the process has exited or has a signal delivered: in both cases, we + * need to cancel any blocking semop(2) call. + */ + remove_process(endpt); } diff --git a/minix/servers/pm/Makefile b/minix/servers/pm/Makefile index 75f4c540e..72a9f43a8 100644 --- a/minix/servers/pm/Makefile +++ b/minix/servers/pm/Makefile @@ -4,7 +4,7 @@ PROG= pm SRCS= main.c forkexit.c exec.c time.c alarm.c \ signal.c utility.c table.c trace.c getset.c misc.c \ - profile.c mcontext.c schedule.c + profile.c mcontext.c schedule.c event.c DPADD+= ${LIBSYS} ${LIBTIMERS} LDADD+= -lsys -ltimers diff --git a/minix/servers/pm/const.h b/minix/servers/pm/const.h index b8c92a549..01be61f0d 100644 --- a/minix/servers/pm/const.h +++ b/minix/servers/pm/const.h @@ -10,6 +10,8 @@ #define NO_TRACER 0 /* process is not being traced */ +#define NO_EVENTSUB ((char)-1) /* no current process event subscriber */ + #define MAX_CLOCK_T ((unsigned long) 1 << ((sizeof(clock_t) * 8) - 1)) #define MAX_SECS ( (clock_t) (MAX_CLOCK_T/system_hz) ) /* max.secs for setitimer() ((2^31-1)/HZ) */ diff --git a/minix/servers/pm/event.c b/minix/servers/pm/event.c new file mode 100644 index 000000000..b78662a3f --- /dev/null +++ b/minix/servers/pm/event.c @@ -0,0 +1,353 @@ +/* + * This file implements a generic process event publish/subscribe facility. + * The facility for use by non-core system services that implement part of the + * userland system call interface. Currently, it supports two events: a + * process catching a signal, and a process being terminated. A subscribing + * service would typically use such events to interrupt a blocking system call + * and/or clean up process-bound resources. As of writing, the only service + * that uses this facility is the System V IPC server. + * + * Each of these events will be published to subscribing services right after + * VFS has acknowledged that it has processed the same event. For each + * subscriber, in turn, the process will be blocked (with the EVENT_CALL flag + * set) until the subscriber acknowledges the event or PM learns that the + * subscriber has died. Thus, each subscriber adds a serialized messaging + * roundtrip for each subscribed event. + * + * The one and only reason for this synchronous, serialized approach is that it + * avoids PM queuing up too many asynchronous messages. In theory, each + * running process may have an event pending, and thus, the serial synchronous + * approach requires NR_PROCS asynsend slots. For a parallel synchronous + * approach, this would increase to (NR_PROCS*NR_SUBS). Worse yet, for an + * asynchronous event notification approach, the number of messages that PM can + * end up queuing is potentially unbounded, so that is certainly not an option. + * At this moment, we expect only one subscriber (the IPC server) which makes + * the serial vs parallel point less relevant. + * + * It is not possible to subscribe to events from certain processes only. If + * a service were to subscribe to process events as part of a system call by + * a process (e.g., semop(2) in the case of the IPC server), it may subscribe + * "too late" and already have missed a signal event for the process calling + * semop(2), for example. Resolving such race conditions would require major + * infrastructure changes. + * + * A server may however change its event subscription mask at runtime, so as to + * limit the number of event messages it receives in a crude fashion. For the + * same race-condition reasons, new subscriptions must always be made when + * processing a message that is *not* a system call potentially affected by + * events. In the case of the IPC server, it may subscribe to events from + * semget(2) but not semop(2). For signal events, the delay call system + * guarantees the safety of this approach; for exit events, the message type + * prioritization does (which is not great; see the TODO item in forkexit.c). + * + * After changing its mask, a subscribing service may still receive messages + * for events it is no longer subscribed to. It should acknowledge these + * messages by sending a reply as usual. + */ + +#include "pm.h" +#include "mproc.h" +#include + +/* + * A realistic upper bound for the number of subscribing services. The process + * event notification system adds a round trip to a service for each subscriber + * and uses asynchronous messaging to boot, so clearly it does not scale to + * numbers larger than this. + */ +#define NR_SUBS 4 + +static struct { + endpoint_t endpt; /* endpoint of subscriber */ + unsigned int mask; /* interests bit mask (PROC_EVENT_) */ + unsigned int waiting; /* # procs blocked on reply from it */ +} subs[NR_SUBS]; + +static unsigned int nsubs = 0; +static unsigned int nested = 0; + +/* + * For the current event of the given process, as determined by its flags, send + * a process event message to the next subscriber, or resume handling the + * event itself if there are no more subscribers to notify. + */ +static void +resume_event(struct mproc * rmp) +{ + message m; + unsigned int i, event; + int r; + + assert(rmp->mp_flags & IN_USE); + assert(rmp->mp_flags & EVENT_CALL); + assert(rmp->mp_eventsub != NO_EVENTSUB); + + /* Which event should we be concerned about? */ + if (rmp->mp_flags & EXITING) + event = PROC_EVENT_EXIT; + else if (rmp->mp_flags & UNPAUSED) + event = PROC_EVENT_SIGNAL; + else + panic("unknown event for flags %x", rmp->mp_flags); + + /* + * If there are additional services interested in this event, send a + * message to the next one. + */ + for (i = rmp->mp_eventsub; i < nsubs; i++, rmp->mp_eventsub++) { + if (subs[i].mask & event) { + memset(&m, 0, sizeof(m)); + m.m_type = PROC_EVENT; + m.m_pm_lsys_proc_event.endpt = rmp->mp_endpoint; + m.m_pm_lsys_proc_event.event = event; + + r = asynsend3(subs[i].endpt, &m, AMF_NOREPLY); + if (r != OK) + panic("asynsend failed: %d", r); + + assert(subs[i].waiting < NR_PROCS); + subs[i].waiting++; + + return; + } + } + + /* No more subscribers to be notified, resume the actual event. */ + rmp->mp_flags &= ~EVENT_CALL; + rmp->mp_eventsub = NO_EVENTSUB; + + if (event == PROC_EVENT_EXIT) + exit_restart(rmp); + else if (event == PROC_EVENT_SIGNAL) + restart_sigs(rmp); +} + +/* + * Remove a subscriber from the set, forcefully if we have to. Ensure that + * any processes currently subject to process event notification are updated + * accordingly, in a way that no services are skipped for process events. + */ +static void +remove_sub(unsigned int slot) +{ + struct mproc *rmp; + unsigned int i; + + /* The loop below needs the remaining items to be kept in order. */ + for (i = slot; i < nsubs - 1; i++) + subs[i] = subs[i + 1]; + nsubs--; + + /* Adjust affected processes' event subscriber indexes to match. */ + for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { + if ((rmp->mp_flags & (IN_USE | EVENT_CALL)) != + (IN_USE | EVENT_CALL)) + continue; + assert(rmp->mp_eventsub != NO_EVENTSUB); + + /* + * While resuming a process could trigger new events, event + * calls always take place after the corresponding VFS calls, + * making this nesting-safe. Check anyway, because if nesting + * does occur, we are in serious (un-debuggable) trouble. + */ + if ((unsigned int)rmp->mp_eventsub == slot) { + nested++; + resume_event(rmp); + nested--; + } else if ((unsigned int)rmp->mp_eventsub > slot) + rmp->mp_eventsub--; + } +} + +/* + * Subscribe to process events. The given event mask denotes the events in + * which the caller is interested. Multiple calls will each replace the mask, + * and a mask of zero will unsubscribe the service from events altogether. + * Return OK on success, EPERM if the caller may not register for events, or + * ENOMEM if all subscriber slots are in use already. + */ +int +do_proceventmask(void) +{ + unsigned int i, mask; + + /* This call is for system services only. */ + if (!(mp->mp_flags & PRIV_PROC)) + return EPERM; + + mask = m_in.m_lsys_pm_proceventmask.mask; + + /* + * First check if we need to update or remove an existing entry. + * We cannot actually remove services for which we are still waiting + * for a reply, so set their mask to zero for later removal instead. + */ + for (i = 0; i < nsubs; i++) { + if (subs[i].endpt == who_e) { + if (mask == 0 && subs[i].waiting == 0) + remove_sub(i); + else + subs[i].mask = mask; + return OK; + } + } + + /* Add a new entry, unless the given mask is empty. */ + if (mask == 0) + return OK; + + /* This case should never trigger. */ + if (nsubs == __arraycount(subs)) { + printf("PM: too many process event subscribers!\n"); + return ENOMEM; + } + + subs[nsubs].endpt = who_e; + subs[nsubs].mask = mask; + nsubs++; + + return OK; +} + +/* + * A subscribing service has replied to a process event message from us, or at + * least that is what should have happened. First make sure of this, and then + * resume event handling for the affected process. + */ +int +do_proc_event_reply(void) +{ + struct mproc *rmp; + endpoint_t endpt; + unsigned int i, event; + int slot; + + assert(nested == 0); + + /* + * Is this an accidental call from a misguided user process? + * Politely tell it to go away. + */ + if (!(mp->mp_flags & PRIV_PROC)) + return ENOSYS; + + /* + * Ensure that we got the reply that we want. Since this code is + * relatively new, produce lots of warnings for cases that should never + * or rarely occur. Later we can just ignore all mismatching replies. + */ + endpt = m_in.m_pm_lsys_proc_event.endpt; + if (pm_isokendpt(endpt, &slot) != OK) { + printf("PM: proc event reply from %d for invalid endpt %d\n", + who_e, endpt); + return SUSPEND; + } + rmp = &mproc[slot]; + if (!(rmp->mp_flags & EVENT_CALL)) { + printf("PM: proc event reply from %d for endpt %d, no event\n", + who_e, endpt); + return SUSPEND; + } + if (rmp->mp_eventsub == NO_EVENTSUB || + (unsigned int)rmp->mp_eventsub >= nsubs) { + printf("PM: proc event reply from %d for endpt %d index %d\n", + who_e, endpt, rmp->mp_eventsub); + return SUSPEND; + } + i = rmp->mp_eventsub; + if (subs[i].endpt != who_e) { + printf("PM: proc event reply for %d from %d instead of %d\n", + endpt, who_e, subs[i].endpt); + return SUSPEND; + } + + if (rmp->mp_flags & EXITING) + event = PROC_EVENT_EXIT; + else if (rmp->mp_flags & UNPAUSED) + event = PROC_EVENT_SIGNAL; + else { + printf("PM: proc event reply from %d for %d, bad flags %x\n", + who_e, endpt, rmp->mp_flags); + return SUSPEND; + } + if (m_in.m_pm_lsys_proc_event.event != event) { + printf("PM: proc event reply from %d for %d for event %d " + "instead of %d\n", who_e, endpt, + m_in.m_pm_lsys_proc_event.event, event); + return SUSPEND; + } + /* + * Do NOT check the event against the subscriber's event mask, since a + * service may have unsubscribed from an event while it has yet to + * process some leftover notifications for that event. We could decide + * not to wait for the replies to those leftover notifications upon + * unsubscription, but that could result in problems upon quick + * resubscription, and such cases may in fact happen in practice. + */ + + assert(subs[i].waiting > 0); + subs[i].waiting--; + + /* + * If we are now no longer waiting for any replies from an already + * unsubscribed (but alive) service, remove it from the set now; this + * will also resume events for the current process. In the normal case + * however, let the current process move on to the next subscriber if + * there are more, and the actual event otherwise. + */ + if (subs[i].mask == 0 && subs[i].waiting == 0) { + remove_sub(i); + } else { + rmp->mp_eventsub++; + + resume_event(rmp); + } + + /* In any case, do not reply to this reply message. */ + return SUSPEND; +} + +/* + * Publish a process event to interested subscribers. The event is determined + * from the process flags. In addition, if the event is a process exit, also + * check if it is a subscribing service that died. + */ +void +publish_event(struct mproc * rmp) +{ + unsigned int i; + + assert(nested == 0); + assert((rmp->mp_flags & (IN_USE | EVENT_CALL)) == IN_USE); + assert(rmp->mp_eventsub == NO_EVENTSUB); + + /* + * If a system service exited, we have to check if it was subscribed to + * process events. If so, we have to remove it from the set and resume + * any processes blocked on an event call to that service. + */ + if ((rmp->mp_flags & (PRIV_PROC | EXITING)) == (PRIV_PROC | EXITING)) { + for (i = 0; i < nsubs; i++) { + if (subs[i].endpt == rmp->mp_endpoint) { + /* + * If the wait count is nonzero, we may or may + * not get additional replies from this service + * later. Those will be ignored. + */ + remove_sub(i); + + break; + } + } + } + + /* + * Either send an event message to the first subscriber, or if there + * are no subscribers, resume processing the event right away. + */ + rmp->mp_flags |= EVENT_CALL; + rmp->mp_eventsub = 0; + + resume_event(rmp); +} diff --git a/minix/servers/pm/forkexit.c b/minix/servers/pm/forkexit.c index 30dfb5a3d..4752d4984 100644 --- a/minix/servers/pm/forkexit.c +++ b/minix/servers/pm/forkexit.c @@ -112,6 +112,8 @@ int do_fork() rmc->mp_interval[i] = 0; /* reset timer intervals */ rmc->mp_started = getticks(); /* remember start time, for ps(1) */ + assert(rmc->mp_eventsub == NO_EVENTSUB); + /* Find a free pid for the child and put it in the table. */ new_pid = get_free_pid(); rmc->mp_pid = new_pid; /* assign pid to child */ @@ -207,6 +209,8 @@ int do_srv_fork() rmc->mp_interval[i] = 0; /* reset timer intervals */ rmc->mp_started = getticks(); /* remember start time, for ps(1) */ + assert(rmc->mp_eventsub == NO_EVENTSUB); + /* Find a free pid for the child and put it in the table. */ new_pid = get_free_pid(); rmc->mp_pid = new_pid; /* assign pid to child */ @@ -306,6 +310,11 @@ int dump_core; /* flag indicating whether to dump core */ /* If the process is not yet stopped, we force a stop here. This means that * the process may still have a delay call pending. For this reason, the main * message loop discards requests from exiting processes. + * + * TODO: make the kernel discard delayed calls upon forced stops for exits, + * so that no service needs to deal with this. Right now it appears that the + * only thing preventing problems with other services is the fact that + * regular messages are prioritized over asynchronous messages. */ if (!(rmp->mp_flags & PROC_STOPPED)) { if ((r = sys_stop(proc_nr_e)) != OK) /* stop the process */ @@ -316,7 +325,7 @@ int dump_core; /* flag indicating whether to dump core */ if((r=vm_willexit(proc_nr_e)) != OK) { panic("exit_proc: vm_willexit failed: %d", r); } - vm_notify_sig_wrapper(rmp->mp_endpoint); + if (proc_nr_e == INIT_PROC_NR) { printf("PM: INIT died with exit status %d; showing stacktrace\n", exit_status); @@ -328,7 +337,9 @@ int dump_core; /* flag indicating whether to dump core */ panic("exit_proc: VFS died: %d", r); } - /* Tell VFS about the exiting process. */ + /* Tell VFS, and after that any matching process event subscribers, about the + * exiting process. + */ memset(&m, 0, sizeof(m)); m.m_type = dump_core ? VFS_PM_DUMPCORE : VFS_PM_EXIT; m.VFS_PM_ENDPT = rmp->mp_endpoint; @@ -397,9 +408,7 @@ int dump_core; /* flag indicating whether to dump core */ /*===========================================================================* * exit_restart * *===========================================================================*/ -void exit_restart(rmp, dump_core) -struct mproc *rmp; /* pointer to the process being terminated */ -int dump_core; /* flag indicating whether to dump core */ +void exit_restart(struct mproc *rmp) { /* VFS replied to our exit or coredump request. Perform the second half of the * exit code. @@ -425,7 +434,7 @@ int dump_core; /* flag indicating whether to dump core */ rmp->mp_scheduler = NONE; /* For core dumps, now is the right time to try to contact the parent. */ - if (dump_core) + if (!(rmp->mp_flags & (TRACE_ZOMBIE | ZOMBIE | TOLD_PARENT))) zombify(rmp); if (!(rmp->mp_flags & PRIV_PROC)) @@ -522,7 +531,8 @@ int do_wait4() /* This child meets the pid test and has exited. */ waited_for = tell_parent(rp, addr); - if (waited_for && !(rp->mp_flags & VFS_CALL)) + if (waited_for && + !(rp->mp_flags & (VFS_CALL | EVENT_CALL))) cleanup(rp); return(SUSPEND); } @@ -633,7 +643,7 @@ int try_cleanup; /* clean up the child when done? */ /* The 'try_cleanup' flag merely saves us from having to be really * careful with statement ordering in exit_proc() and exit_restart(). */ - if (try_cleanup && !(child->mp_flags & VFS_CALL)) + if (try_cleanup && !(child->mp_flags & (VFS_CALL | EVENT_CALL))) cleanup(child); } else { diff --git a/minix/servers/pm/main.c b/minix/servers/pm/main.c index 86dee877a..814601502 100644 --- a/minix/servers/pm/main.c +++ b/minix/servers/pm/main.c @@ -86,6 +86,8 @@ int main() handle_vfs_reply(); result = SUSPEND; /* don't reply */ + } else if (call_nr == PROC_EVENT_REPLY) { + result = do_proc_event_reply(); } else if (IS_PM_CALL(call_nr)) { /* If the system call number is valid, perform the call. */ call_index = (unsigned int) (call_nr - PM_BASE); @@ -146,6 +148,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) init_timer(&rmp->mp_timer); rmp->mp_magic = MP_MAGIC; rmp->mp_sigact = mpsigact[rmp - mproc]; + rmp->mp_eventsub = NO_EVENTSUB; } /* Build the set of signals which cause core dumps, and the set of signals @@ -345,18 +348,18 @@ static void handle_vfs_reply() break; - case VFS_PM_EXIT_REPLY: - exit_restart(rmp, FALSE /*dump_core*/); - - break; - case VFS_PM_CORE_REPLY: if (m_in.VFS_PM_STATUS == OK) rmp->mp_sigstatus |= WCOREFLAG; - exit_restart(rmp, TRUE /*dump_core*/); + /* FALLTHROUGH */ + case VFS_PM_EXIT_REPLY: + assert(rmp->mp_flags & EXITING); - break; + /* Publish the exit event. Continue exiting the process after that. */ + publish_event(rmp); + + return; /* do not take the default action */ case VFS_PM_FORK_REPLY: /* Schedule the newly created process ... */ @@ -401,7 +404,10 @@ static void handle_vfs_reply() /* Process is now unpaused */ rmp->mp_flags |= UNPAUSED; - break; + /* Publish the signal event. Continue with signals only after that. */ + publish_event(rmp); + + return; /* do not take the default action */ default: panic("handle_vfs_reply: unknown reply code: %d", call_nr); diff --git a/minix/servers/pm/mproc.h b/minix/servers/pm/mproc.h index 02069fab9..d279aa2b7 100644 --- a/minix/servers/pm/mproc.h +++ b/minix/servers/pm/mproc.h @@ -24,6 +24,7 @@ EXTERN ixfer_sigaction mpsigact[NR_PROCS][_NSIG]; EXTERN struct mproc { char mp_exitstatus; /* storage for status when process exits */ char mp_sigstatus; /* storage for signal # for killed procs */ + char mp_eventsub; /* process event subscriber, or NO_EVENTSUB */ pid_t mp_pid; /* process id */ endpoint_t mp_endpoint; /* kernel endpoint id */ pid_t mp_procgrp; /* pid of process group (used for signals) */ @@ -98,5 +99,6 @@ EXTERN struct mproc { #define TRACE_ZOMBIE 0x10000 /* waiting for tracer to issue WAIT4 call */ #define DELAY_CALL 0x20000 /* waiting for call before sending signal */ #define TAINTED 0x40000 /* process is 'tainted' */ +#define EVENT_CALL 0x80000 /* waiting for process event subscriber */ #define MP_MAGIC 0xC0FFEE0 diff --git a/minix/servers/pm/proto.h b/minix/servers/pm/proto.h index 175ddbcdb..3a8554387 100644 --- a/minix/servers/pm/proto.h +++ b/minix/servers/pm/proto.h @@ -9,6 +9,11 @@ int do_itimer(void); void set_alarm(struct mproc *rmp, clock_t ticks); void check_vtimer(int proc_nr, int sig); +/* event.c */ +int do_proceventmask(void); +int do_proc_event_reply(void); +void publish_event(struct mproc *rmp); + /* exec.c */ int do_exec(void); int do_newexec(void); @@ -21,7 +26,7 @@ int do_fork(void); int do_srv_fork(void); int do_exit(void); void exit_proc(struct mproc *rmp, int exit_status, int dump_core); -void exit_restart(struct mproc *rmp, int dump_core); +void exit_restart(struct mproc *rmp); int do_wait4(void); int wait_test(struct mproc *rmp, struct mproc *child); @@ -68,7 +73,6 @@ int do_sigreturn(void); int do_sigsuspend(void); void check_pending(struct mproc *rmp); void restart_sigs(struct mproc *rmp); -void vm_notify_sig_wrapper(endpoint_t ep); /* time.c */ int do_stime(void); diff --git a/minix/servers/pm/signal.c b/minix/servers/pm/signal.c index d793d8a15..b766d4e76 100644 --- a/minix/servers/pm/signal.c +++ b/minix/servers/pm/signal.c @@ -43,7 +43,7 @@ int do_sigaction(void) struct sigaction svec; struct sigaction *svp; - assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED))); + assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED | EVENT_CALL))); sig_nr = m_in.m_lc_pm_sig.nr; if (sig_nr == SIGKILL) return(OK); @@ -90,7 +90,7 @@ int do_sigaction(void) *===========================================================================*/ int do_sigpending(void) { - assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED))); + assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED | EVENT_CALL))); mp->mp_reply.m_pm_lc_sigset.set = mp->mp_sigpending; return OK; @@ -114,7 +114,7 @@ int do_sigprocmask(void) sigset_t set; int i; - assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED))); + assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED | EVENT_CALL))); set = m_in.m_lc_pm_sigset.set; mp->mp_reply.m_pm_lc_sigset.set = mp->mp_sigmask; @@ -159,7 +159,7 @@ int do_sigprocmask(void) *===========================================================================*/ int do_sigsuspend(void) { - assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED))); + assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED | EVENT_CALL))); mp->mp_sigmask2 = mp->mp_sigmask; /* save the old mask */ mp->mp_sigmask = m_in.m_lc_pm_sigset.set; @@ -180,7 +180,7 @@ int do_sigreturn(void) */ int r; - assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED))); + assert(!(mp->mp_flags & (PROC_STOPPED | VFS_CALL | UNPAUSED | EVENT_CALL))); mp->mp_sigmask = m_in.m_lc_pm_sigset.set; sigdelset(&mp->mp_sigmask, SIGKILL); @@ -270,11 +270,13 @@ static void try_resume_proc(struct mproc *rmp) assert(rmp->mp_flags & PROC_STOPPED); - /* If the process is blocked on a VFS call, do not resume it now. Most likely * it will be unpausing, in which case the process must remain stopped. - * Otherwise, it will still be resumed once the VFS call returns. If the - * process has died, do not resume it either. + /* If the process is blocked on a VFS call or a process event notification, + * do not resume it now. Most likely it will be unpausing, in which case the + * process must remain stopped. Otherwise, it will still be resumed once the + * VFS or event call is replied to. If the process has died, do not resume + * it either. */ - if (rmp->mp_flags & (VFS_CALL | EXITING)) + if (rmp->mp_flags & (VFS_CALL | EVENT_CALL | EXITING)) return; if ((r = sys_resume(rmp->mp_endpoint)) != OK) @@ -354,7 +356,7 @@ int process_ksig(endpoint_t proc_nr_e, int signo) * that case, we must wait with further signal processing until VFS has * replied. Stop the process. */ - if (rmp->mp_flags & VFS_CALL) { + if (rmp->mp_flags & (VFS_CALL | EVENT_CALL)) { stop_proc(rmp, FALSE /*may_delay*/); return OK; @@ -418,17 +420,17 @@ int ksig; /* non-zero means signal comes from kernel */ return; } - if (rmp->mp_flags & VFS_CALL) { + if (rmp->mp_flags & (VFS_CALL | EVENT_CALL)) { sigaddset(&rmp->mp_sigpending, signo); if(ksig) sigaddset(&rmp->mp_ksigpending, signo); - /* Process the signal once VFS replies. Stop the process in the - * meantime, so that it cannot make another call after the VFS reply - * comes in but before we look at its signals again. Since we always - * stop the process to deliver signals during a VFS call, the - * PROC_STOPPED flag doubles as an indicator in restart_sigs() that - * signals must be rechecked after a VFS reply comes in. + /* Process the signal once VFS and process event subscribers reply. + * Stop the process in the meantime, so that it cannot make another + * call after the VFS reply comes in but before we look at its signals + * again. Since we always stop the process to deliver signals during a + * VFS or event call, the PROC_STOPPED flag doubles as an indicator in + * restart_sigs() that signals must be rechecked after a reply arrives. */ if (!(rmp->mp_flags & (PROC_STOPPED | DELAY_CALL))) { /* If a VFS call is ongoing and the process is not yet stopped, @@ -663,7 +665,7 @@ register struct mproc *rmp; sigdelset(&rmp->mp_ksigpending, i); sig_proc(rmp, i, FALSE /*trace*/, ksig); - if (rmp->mp_flags & VFS_CALL) { + if (rmp->mp_flags & (VFS_CALL | EVENT_CALL)) { /* Signals must be rechecked upon return from the new * VFS call, unless the process was killed. In both * cases, the process is stopped. @@ -684,7 +686,7 @@ struct mproc *rmp; /* VFS has replied to a request from us; do signal-related work. */ - if (rmp->mp_flags & (VFS_CALL | EXITING)) return; + if (rmp->mp_flags & (VFS_CALL | EVENT_CALL | EXITING)) return; if (rmp->mp_flags & TRACE_EXIT) { /* Tracer requested exit with specific exit value */ @@ -720,7 +722,7 @@ struct mproc *rmp; /* which process */ */ message m; - assert(!(rmp->mp_flags & VFS_CALL)); + assert(!(rmp->mp_flags & (VFS_CALL | EVENT_CALL))); /* If the UNPAUSED flag is set, VFS replied to an earlier unpause request. */ if (rmp->mp_flags & UNPAUSED) { @@ -744,9 +746,10 @@ struct mproc *rmp; /* which process */ return TRUE; } - /* Not paused in PM. Let VFS try to unpause the process. The process needs to - * be stopped for this. If it is not already stopped, try to stop it now. If - * that does not succeed immediately, postpone signal delivery. + /* Not paused in PM. Let VFS, and after that any matching process event + * subscribers, try to unpause the process. The process needs to be stopped + * for this. If it is not already stopped, try to stop it now. If that does + * not succeed immediately, postpone signal delivery. */ if (!(rmp->mp_flags & PROC_STOPPED) && !stop_proc(rmp, TRUE /*may_delay*/)) return FALSE; @@ -757,9 +760,6 @@ struct mproc *rmp; /* which process */ tell_vfs(rmp, &m); - /* Also tell VM. */ - vm_notify_sig_wrapper(rmp->mp_endpoint); - return FALSE; } @@ -845,28 +845,3 @@ int signo; /* signal to send to process (1 to _NSIG-1) */ return(TRUE); } - -/*===========================================================================* - * vm_notify_sig_wrapper * - *===========================================================================*/ -void vm_notify_sig_wrapper(endpoint_t ep) -{ -/* get IPC's endpoint, - * the reason that we directly get the endpoint - * instead of from DS server is that otherwise - * it will cause deadlock between PM, VM and DS. - */ - struct mproc *rmp; - endpoint_t ipc_ep = 0; - - for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { - if (!(rmp->mp_flags & IN_USE)) - continue; - if (!strcmp(rmp->mp_name, "ipc")) { - ipc_ep = rmp->mp_endpoint; - vm_notify_sig(ep, ipc_ep); - - return; - } - } -} diff --git a/minix/servers/pm/table.c b/minix/servers/pm/table.c index d730a276f..8d9b85e39 100644 --- a/minix/servers/pm/table.c +++ b/minix/servers/pm/table.c @@ -51,6 +51,7 @@ int (* const call_vec[NR_PM_CALLS])(void) = { CALL(PM_REBOOT) = do_reboot, /* reboot(2) */ CALL(PM_SVRCTL) = do_svrctl, /* svrctl(2) */ CALL(PM_SPROF) = do_sprofile, /* sprofile(2) */ + CALL(PM_PROCEVENTMASK) = do_proceventmask, /* proceventmask(2) */ CALL(PM_SRV_FORK) = do_srv_fork, /* srv_fork(2) */ CALL(PM_SRV_KILL) = do_srv_kill, /* srv_kill(2) */ CALL(PM_EXEC_NEW) = do_newexec, diff --git a/minix/servers/pm/trace.c b/minix/servers/pm/trace.c index e2498a882..f742a0a0d 100644 --- a/minix/servers/pm/trace.c +++ b/minix/servers/pm/trace.c @@ -145,8 +145,8 @@ int do_trace() case T_EXIT: /* exit */ child->mp_flags |= TRACE_EXIT; - /* Defer the exit if the traced process has an VFS call pending. */ - if (child->mp_flags & VFS_CALL) + /* Defer the exit if the traced process has a call pending. */ + if (child->mp_flags & (VFS_CALL | EVENT_CALL)) child->mp_exitstatus = m_in.m_lc_pm_ptrace.data; /* save it */ else exit_proc(child, m_in.m_lc_pm_ptrace.data, diff --git a/minix/servers/pm/utility.c b/minix/servers/pm/utility.c index c8cd9a966..04a4b1c2f 100644 --- a/minix/servers/pm/utility.c +++ b/minix/servers/pm/utility.c @@ -128,7 +128,7 @@ message *m_ptr; */ int r; - if (rmp->mp_flags & VFS_CALL) + if (rmp->mp_flags & (VFS_CALL | EVENT_CALL)) panic("tell_vfs: not idle: %d", m_ptr->m_type); r = asynsend3(VFS_PROC_NR, m_ptr, AMF_NOREPLY); diff --git a/minix/servers/vm/Makefile b/minix/servers/vm/Makefile index bd874a732..4cd45a530 100644 --- a/minix/servers/vm/Makefile +++ b/minix/servers/vm/Makefile @@ -4,7 +4,7 @@ PROG= vm SRCS= main.c alloc.c utility.c exit.c fork.c break.c \ mmap.c slaballoc.c region.c pagefaults.c pagetable.c \ - rs.c queryexit.c pb.c regionavl.c \ + rs.c pb.c regionavl.c \ mem_anon.c mem_directphys.c mem_anon_contig.c mem_shared.c \ mem_cache.c cache.c vfs.c mem_file.c fdref.c acl.c diff --git a/minix/servers/vm/main.c b/minix/servers/vm/main.c index 9f939da8c..d6f5d7b55 100644 --- a/minix/servers/vm/main.c +++ b/minix/servers/vm/main.c @@ -545,7 +545,6 @@ void init_vm(void) CALLMAP(VM_FORK, do_fork); CALLMAP(VM_BRK, do_brk); CALLMAP(VM_WILLEXIT, do_willexit); - CALLMAP(VM_NOTIFY_SIG, do_notify_sig); CALLMAP(VM_PROCCTL, do_procctl_notrans); @@ -566,8 +565,6 @@ void init_vm(void) CALLMAP(VM_SHM_UNMAP, do_munmap); CALLMAP(VM_GETREF, do_get_refcount); CALLMAP(VM_INFO, do_info); - CALLMAP(VM_QUERY_EXIT, do_query_exit); - CALLMAP(VM_WATCH_EXIT, do_watch_exit); /* Cache blocks. */ CALLMAP(VM_MAPCACHEPAGE, do_mapcache); @@ -578,9 +575,6 @@ void init_vm(void) /* getrusage */ CALLMAP(VM_GETRUSAGE, do_getrusage); - /* Initialize the structures for queryexit */ - init_query_exit(); - /* Mark VM instances. */ num_vm_instances = 1; vmproc[VM_PROC_NR].vm_flags |= VMF_VM_INSTANCE; diff --git a/minix/servers/vm/proto.h b/minix/servers/vm/proto.h index c46eb5d06..ba06f05ce 100644 --- a/minix/servers/vm/proto.h +++ b/minix/servers/vm/proto.h @@ -197,12 +197,6 @@ int do_rs_prepare(message *m); int do_rs_update(message *m); int do_rs_memctl(message *m); -/* queryexit.c */ -int do_query_exit(message *m); -int do_watch_exit(message *m); -int do_notify_sig(message *m); -void init_query_exit(void); - /* pb.c */ struct phys_block *pb_new(phys_bytes phys); void pb_free(struct phys_block *); diff --git a/minix/servers/vm/queryexit.c b/minix/servers/vm/queryexit.c deleted file mode 100644 index 8f21da389..000000000 --- a/minix/servers/vm/queryexit.c +++ /dev/null @@ -1,144 +0,0 @@ - -#define _SYSTEM 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "glo.h" -#include "proto.h" -#include "util.h" - -struct query_exit_struct { - int avail; - endpoint_t ep; -}; -static struct query_exit_struct array[NR_PROCS]; - -/*===========================================================================* - * do_query_exit * - *===========================================================================*/ -int do_query_exit(message *m) -{ - int i, nr; - endpoint_t ep = NONE; - - for (i = 0; i < NR_PROCS; i++) { - if (!array[i].avail) { - array[i].avail = 1; - ep = array[i].ep; - array[i].ep = 0; - - break; - } - } - - nr = 0; - for (i = 0; i < NR_PROCS; i++) { - if (!array[i].avail) - nr++; - } - m->m_lsys_vm_query_exit.ret_pt = ep; - m->m_lsys_vm_query_exit.is_more = (nr > 0); - - return OK; -} - -/*===========================================================================* - * do_notify_sig * - *===========================================================================*/ -int do_notify_sig(message *m) -{ - int i, avails = 0; - endpoint_t ep = m->VM_NOTIFY_SIG_ENDPOINT; - endpoint_t ipc_ep = m->VM_NOTIFY_SIG_IPC; - int r; - struct vmproc *vmp; - int pslot; - - if(vm_isokendpt(ep, &pslot) != OK) return ESRCH; - vmp = &vmproc[pslot]; - - /* Only record the event if we've been asked to report it. */ - if(!(vmp->vm_flags & VMF_WATCHEXIT)) - return OK; - - for (i = 0; i < NR_PROCS; i++) { - /* its signal is already here */ - if (!array[i].avail && array[i].ep == ep) - goto out; - if (array[i].avail) - avails++; - } - if (!avails) { - /* no slot for signals, unlikely */ - printf("VM: no slot for signals!\n"); - return ENOMEM; - } - - for (i = 0; i < NR_PROCS; i++) { - if (array[i].avail) { - array[i].avail = 0; - array[i].ep = ep; - - break; - } - } - -out: - /* only care when IPC server starts up, - * and bypass the process to be signal is IPC itself. - */ - if (ipc_ep != 0 && ep != ipc_ep) { - r = ipc_notify(ipc_ep); - if (r != OK) - printf("VM: ipc_notify error!\n"); - } - return OK; -} - -/*===========================================================================* - * do_watch_exit * - *===========================================================================*/ -int do_watch_exit(message *m) -{ - endpoint_t e = m->m_lsys_vm_watch_exit.ep; - struct vmproc *vmp; - int p; - if(vm_isokendpt(e, &p) != OK) return ESRCH; - vmp = &vmproc[p]; - vmp->vm_flags |= VMF_WATCHEXIT; - - return OK; -} - -/*===========================================================================* - * init_query_exit * - *===========================================================================*/ -void init_query_exit(void) -{ - int i; - - for (i = 0; i < NR_PROCS; i++) { - array[i].avail = 1; - array[i].ep = 0; - } -} - diff --git a/minix/servers/vm/vmproc.h b/minix/servers/vm/vmproc.h index 0ec2a8219..1a562d508 100644 --- a/minix/servers/vm/vmproc.h +++ b/minix/servers/vm/vmproc.h @@ -34,7 +34,6 @@ struct vmproc { /* Bits for vm_flags */ #define VMF_INUSE 0x001 /* slot contains a process */ #define VMF_EXITING 0x002 /* PM is cleaning up this process */ -#define VMF_WATCHEXIT 0x008 /* Store in queryexit table */ #define VMF_VM_INSTANCE 0x010 /* This is a VM process instance */ #endif