ref: e0e889fb69a6d4d3f2332244ef4f79f900a66d84
dir: /cleanup.c/
/* cleanup.c - VMX SMP cleanup handling */
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "dat.h"
#include "fns.h"
static int parent_pid;
static int child_pids[MAXVCPU];
static int nchildren;
extern int ctlfd, regsfd, mapfd, waitfd;
extern int kbdpipe[2];
extern int mousepipe[2];
extern int uartpipe[2][2];
extern int uarttxpipe[2][2];
extern int wakepipe[MAXVCPU][2];
extern int hltpipe[MAXVCPU][2];
/*
* Stop and release VMX context - each process does this for its own
*/
static void
cleanup_vmx(void)
{
extern IOApic *ioapic;
extern IpiQueue *ipiqueue;
extern PciShared *pcishared;
extern VIOShared *vioshared;
/* Detach shared segments first */
if(ioapic != nil){ segdetach(ioapic); ioapic = nil; }
if(ipiqueue != nil){ segdetach(ipiqueue); ipiqueue = nil; }
if(pcishared != nil){ segdetach(pcishared); pcishared = nil; }
if(vioshared != nil){ segdetach(vioshared); vioshared = nil; }
if(ctlfd >= 0){
write(ctlfd, "stop", 4);
write(ctlfd, "quit", 4);
}
if(waitfd >= 0){ close(waitfd); waitfd = -1; }
if(mapfd >= 0){ close(mapfd); mapfd = -1; }
if(regsfd >= 0){ close(regsfd); regsfd = -1; }
if(ctlfd >= 0){ close(ctlfd); ctlfd = -1; }
extern char name[128];
char buf[128];
snprint(buf, sizeof(buf), "#X/%s/ctl", name);
remove(buf);
snprint(buf, sizeof(buf), "#X/%s", name);
remove(buf);
}
/*
* Remove shared segments - parent only
*/
static void
cleanup_shared(void)
{
if(vmx_segprefix == nil)
return;
rmseg("ioapic");
rmseg("ipi");
rmseg("pci");
rmseg("vio");
free(vmx_segprefix);
vmx_segprefix = nil;
}
/*
* Close all pipes - parent only
*/
static void
cleanup_pipes(void)
{
int i;
for(i = 0; i < MAXVCPU; i++){
if(wakepipe[i][0] >= 0) close(wakepipe[i][0]);
if(wakepipe[i][1] >= 0) close(wakepipe[i][1]);
if(hltpipe[i][0] >= 0) close(hltpipe[i][0]);
if(hltpipe[i][1] >= 0) close(hltpipe[i][1]);
wakepipe[i][0] = wakepipe[i][1] = -1;
hltpipe[i][0] = hltpipe[i][1] = -1;
}
if(kbdpipe[0] >= 0) close(kbdpipe[0]);
if(kbdpipe[1] >= 0) close(kbdpipe[1]);
kbdpipe[0] = kbdpipe[1] = -1;
if(mousepipe[0] >= 0) close(mousepipe[0]);
if(mousepipe[1] >= 0) close(mousepipe[1]);
mousepipe[0] = mousepipe[1] = -1;
for(i = 0; i < 2; i++){
if(uartpipe[i][0] >= 0) close(uartpipe[i][0]);
if(uartpipe[i][1] >= 0) close(uartpipe[i][1]);
if(uarttxpipe[i][0] >= 0) close(uarttxpipe[i][0]);
if(uarttxpipe[i][1] >= 0) close(uarttxpipe[i][1]);
uartpipe[i][0] = uartpipe[i][1] = -1;
uarttxpipe[i][0] = uarttxpipe[i][1] = -1;
}
}
/*
* Kill all child CPU processes
*/
static void
killchildren(void)
{
int i;
Waitmsg *w;
for(i = 0; i < nchildren; i++){
if(child_pids[i] > 0)
postnote(PNPROC, child_pids[i], "kill");
}
/* Actually wait for them to exit */
for(i = 0; i < nchildren; i++){
if(child_pids[i] > 0){
w = wait();
if(w != nil)
free(w);
}
}
}
/*
* Full cleanup - called on exit
*/
void
vmx_cleanup(void)
{
int isparent = (getpid() == parent_pid);
dprint("vmx_cleanup: pid=%d isparent=%d\n", getpid(), isparent);
if(isparent)
killchildren(); /* This should sleep(100) internally */
cleanup_vmx();
if(isparent){
sleep(200); /* Extra wait for children to fully exit */
cleanup_pipes();
cleanup_shared();
}
}
/*
* atexit handler
*/
static void
vmx_atexit(void)
{
vmx_cleanup();
}
/*
* Note handler - catch Del, kill, hangup
*/
int
vmx_notehandler(void *, char *note)
{
dprint("NOTE: %s (pid %d)\n", note, getpid());
if(strcmp(note, "interrupt") == 0 ||
strcmp(note, "kill") == 0 ||
strcmp(note, "hangup") == 0){
vmx_cleanup();
}
return 0; /* Note not handled, pass to default */
}
/*
* Register cleanup handlers - call early in threadmain()
*/
void
vmx_cleanup_init(void)
{
parent_pid = getpid();
nchildren = 0;
memset(child_pids, 0, sizeof(child_pids));
/* Use threadnotify for libthread programs */
threadnotify(vmx_notehandler, 1);
atexit(vmx_atexit);
}
/*
* Register a child process - call from forkcpu() in parent
*/
void
vmx_register_child(int pid)
{
if(nchildren < MAXVCPU)
child_pids[nchildren++] = pid;
}