shithub: vmxsmp

ref: e0e889fb69a6d4d3f2332244ef4f79f900a66d84
dir: /cleanup.c/

View raw version
/* 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;
}