From: David van Moolenbroek Date: Sat, 12 Dec 2015 17:22:00 +0000 (+0000) Subject: PM: generic process event publish/subscribe system X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=refs%2Fchanges%2F61%2F3261%2F3;p=minix.git PM: generic process event publish/subscribe system Now that there are services other than PM and VFS that implement userland system calls directly, these services may need to know about events related to user processes. In particular, signal delivery may have to interrupt blocking system calls, and certain cleanup tasks may have to be performed after a user process exits. This patch aims to implement a generic, lasting solution for this problem, by allowing services to subscribe to "signal delivered" and/or "process exit" events from PM. PM publishes such events by sending messages to its subscribed services, which must then reply an acknowledgment message. For now, only the two aforementioned events are implemented, and only the IPC service makes use of the process event facility. The new process event publish/subscribe system replaces the previous VM notify-sig/watch-exit/query-exit system, which was unsound: 1) it allowed subscription to events from individual processes, and suffered from fundamental race conditions as a result; 2) it relied on "not too many" processes making use of the IPC server functionality in order to avoid loss of notifications. In addition, it had the "ipc" process name hardcoded, did not distinguish between signal delivery and exits, and added a roundtrip to VM for all events from all processes. Change-Id: I75ebad4bc54e646c6433f473294cb4003b2c3430 --- 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