void deadboot (void *p) { struct bootinfo *boot = p; size_t i; munmap (boot->argv, boot->argvlen); munmap (boot->envp, boot->envplen); for (i = 0; i < boot->dtablesize; ++i) mach_port_deallocate (mach_task_self (), boot->dtable[i]); for (i = 0; i < boot->nports; ++i) mach_port_deallocate (mach_task_self (), boot->portarray[i]); munmap (boot->portarray, boot->nports * sizeof (mach_port_t)); munmap (boot->intarray, boot->nints * sizeof (int)); /* See if we are going away and this was the last thing keeping us up. */ if (ports_count_class (trivfs_cntl_portclasses[0]) == 0) { /* We have no fsys control port, so we are detached from the parent filesystem. Maybe we have no users left either. */ if (ports_count_class (trivfs_protid_portclasses[0]) == 0) { /* We have no user ports left. Are we still listening for exec_startup RPCs from any tasks we already started? */ if (ports_count_class (execboot_portclass) == 0) /* Nobody talking. Time to die. */ exit (0); ports_enable_class (execboot_portclass); } ports_enable_class (trivfs_protid_portclasses[0]); } ports_enable_class (trivfs_cntl_portclasses[0]); }
int main (int argc, char **argv) { error_t err; mach_port_t bootstrap; struct trivfs_control *fsys; fifo_pipe_class = stream_pipe_class; argp_parse (&argp, argc, argv, 0, 0, 0); task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) error (1, 0, "must be started as a translator"); /* Reply to our parent */ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys); mach_port_deallocate (mach_task_self (), bootstrap); if (err) error (3, err, "Contacting parent"); /* Launch. */ do { ports_enable_class (fsys->protid_class); ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer, 30*1000, 5*60*1000, 0); } while (ports_count_class (fsys->protid_class) > 0); return 0; }
error_t trivfs_goaway (struct trivfs_control *cntl, int flags) { if (flags & FSYS_GOAWAY_FORCE) exit (0); else { /* Stop new requests. */ ports_inhibit_class_rpcs (pfinet_cntl_portclasses[0]); ports_inhibit_class_rpcs (pfinet_protid_portclasses[0]); ports_inhibit_class_rpcs (socketport_class); if (ports_count_class (socketport_class) != 0) { /* We won't go away, so start things going again... */ ports_enable_class (socketport_class); ports_resume_class_rpcs (pfinet_cntl_portclasses[0]); ports_resume_class_rpcs (pfinet_protid_portclasses[0]); return EBUSY; } /* There are no sockets, so we can die without breaking anybody too badly. We don't let user ports on the /servers/socket/2 file keep us alive because those get cached in every process that ever makes a PF_INET socket, libc copes with getting MACH_SEND_INVALID_DEST and looking up the new translator. */ exit (0); } }
error_t trivfs_goaway (struct trivfs_control *fsys, int flags) { struct dev *const device = fsys->hook; error_t err; int force = (flags & FSYS_GOAWAY_FORCE); int nosync = (flags & FSYS_GOAWAY_NOSYNC); struct port_class *root_port_class = fsys->protid_class; mutex_lock (&device->lock); if (device->store == NULL) /* The device is not actually open. XXX note that exitting here nukes non-io users, like someone in the middle of a stat who will get SIGLOST or something. */ exit (0); /* Wait until all pending rpcs are done. */ err = ports_inhibit_class_rpcs (root_port_class); if (err == EINTR || (err && !force)) { mutex_unlock (&device->lock); return err; } if (force && nosync) /* Exit with extreme prejudice. */ exit (0); if (!force && ports_count_class (root_port_class) > 0) /* Still users, so don't exit. */ goto busy; if (! nosync) /* Sync the device here, if necessary, so that closing it won't result in any I/O (which could get hung up trying to use one of our pagers). */ dev_sync (device, 1); /* devpager_shutdown may sync the pagers as side-effect (if NOSYNC is 0), so we put that first in this test. */ if (dev_stop_paging (device, nosync) || force) /* Bye-bye. */ { if (! nosync) /* If NOSYNC is true, we don't close DEV, as that could cause data to be written back. */ dev_close (device); exit (0); } busy: /* Allow normal operations to proceed. */ ports_enable_class (root_port_class); ports_resume_class_rpcs (root_port_class); mutex_unlock (&device->lock); /* Complain that there are still users. */ return EBUSY; }
error_t trivfs_goaway (struct trivfs_control *fsys, int flags) { int count; /* Stop new requests. */ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]); ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]); /* Are there any extant user ports for the /servers/exec file? */ count = ports_count_class (trivfs_protid_portclasses[0]); if (count == 0 || (flags & FSYS_GOAWAY_FORCE)) { /* No users. Disconnect from the filesystem. */ mach_port_deallocate (mach_task_self (), fsys->underlying); /* Are there remaining exec_startup RPCs to answer? */ count = ports_count_class (execboot_portclass); if (count == 0) /* Nope. We got no reason to live. */ exit (0); /* Continue servicing tasks starting up. */ ports_enable_class (execboot_portclass); /* No more communication with the parent filesystem. */ ports_destroy_right (fsys); return 0; } else { /* We won't go away, so start things going again... */ ports_enable_class (trivfs_protid_portclasses[0]); ports_resume_class_rpcs (trivfs_cntl_portclasses[0]); ports_resume_class_rpcs (trivfs_protid_portclasses[0]); return EBUSY; } }
/* someone asks us to die */ error_t trivfs_goaway(struct trivfs_control *cntl, int flags) { const int protid_users = ports_count_class(cntl->protid_class); const int force = flags & FSYS_GOAWAY_FORCE; const int nosync = flags & FSYS_GOAWAY_NOSYNC; /* does our live have a meaning yet? */ if(protid_users && !force) { /* yeah, have to toil a bit longer -> blow it off */ ports_enable_class(cntl->protid_class); return EBUSY; } /* nope, that was it */ if(!nosync) /* we use a liberal interpretation of NOSYNC here */ cleanup_module(); /* "...as though it never existed..." */ exit(0); /* "...now I will just say goodbye" */ }