/* * 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; }
/* * 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); }
int remove_sub(const csc& pathL) { return remove_sub(pathL, false); }
int rmdir_sub(const csc& pathL) { return remove_sub(pathL, true); }
/* * 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; }