summaryrefslogblamecommitdiffstats
path: root/private/mvdm/softpc.new/base/ccpu386/ntthread.c
blob: 48f79d8d9c712347e0f6ce44d1f5693a24457ac1 (plain) (tree)




























































































































































































































































                                                                                                                                                    
#include <windows.h>
#include "insignia.h"
#include "host_def.h"

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

#define BADID   ((DWORD)-1)

#define MAXDEPTH    20

typedef struct {
    IS32 level;
    jmp_buf sims[MAXDEPTH];
    jmp_buf excepts[MAXDEPTH];
} ThreadSimBuf, *ThreadSimBufPtr;
    
typedef struct tids {
    DWORD tid;
    struct tids *next;
} TidList, *TidListPtr;

#define TIDNULL ((TidListPtr)0)

TidListPtr tidlist = TIDNULL;

void ccpu386InitThreadStuff();
void ccpu386foundnewthread();
void ccpu386newthread();
void ccpu386exitthread();
jmp_buf *ccpu386SimulatePtr();
void ccpu386Unsimulate();
jmp_buf *ccpu386ThrdExptnPtr();
void ccpu386GotoThrdExptnPt();

DWORD ccpuSimId = BADID;
IBOOL potentialNewThread = FALSE;

void ccpu386InitThreadStuff()
{
    static TidList lhead;

    ccpuSimId = TlsAlloc();

    if (ccpuSimId == BADID)
        fprintf(stderr, "ccpu386InitThreadStuff: TlsAlloc() failed\n");

    lhead.tid = GetCurrentThreadId();
    lhead.next = TIDNULL;
    tidlist = &lhead;

    ccpu386foundnewthread();     /* for main thread */

}

// what we'd really like to do at create thread time if we could be called
// in the correct context.
void ccpu386foundnewthread()
{
    ThreadSimBufPtr simstack;
    TidListPtr tp;

    if (ccpuSimId == BADID)
    {
        fprintf(stderr, "ccpu386foundnewthread id:%#x called with Bad Id\n", GetCurrentThreadId());
        return;
    }
    // get buffer for this thread to do sim/unsim on.
    simstack = (ThreadSimBufPtr)malloc(sizeof(ThreadSimBuf));

    if (simstack == (ThreadSimBufPtr)0)
    {
        fprintf(stderr, "ccpu386foundnewthread id:%#x cant malloc %d bytes. Err:%#x\n", GetCurrentThreadId(), sizeof(ThreadSimBuf), GetLastError());
        return;
    }
    simstack->level = 0;
    if (!TlsSetValue(ccpuSimId, simstack))
    {
        fprintf(stderr, "ccpu386foundnewthread id:%#x simid %#x TlsSetValue failed (err:%#x)\n", GetCurrentThreadId(), ccpuSimId, GetLastError());
        return;
    }
}

/* just set bool to be checked in simulate which will be in new thread context*/
void ccpu386newthread()
{
    potentialNewThread = TRUE;
}

void ccpu386exitthread()
{
    ThreadSimBufPtr simstack;
    TidListPtr tp, prev;

    if (ccpuSimId == BADID)
    {
        fprintf(stderr, "ccpu386exitthread id:%#x called with Bad Id\n", GetCurrentThreadId());
        return;
    }
    simstack = (ThreadSimBufPtr)TlsGetValue(ccpuSimId);
    if (simstack == (ThreadSimBufPtr)0)
    {
        fprintf(stderr, "ccpu386exitthread tid:%#x simid %#x TlsGetValue failed (err:%#x)\n", GetCurrentThreadId(), ccpuSimId, GetLastError());
        return;
    }
    free(simstack);     //lose host sim memory for this thread 

    prev = tidlist;
    tp = tidlist->next;  // assume wont lose main thread

    // remove tid from list of known threads
    while(tp != TIDNULL)
    {
        if (tp->tid == GetCurrentThreadId())
        {
            prev->next = tp->next;  /* take current node out of chain */
            free(tp);
            break;
        }
        prev = tp;
        tp = tp->next;
    }
}

jmp_buf *ccpu386SimulatePtr()
{
    ThreadSimBufPtr simstack;
    TidListPtr tp, prev;

    if (ccpuSimId == BADID)
    {
        fprintf(stderr, "ccpu386SimulatePtr id:%#x called with Bad Id\n", GetCurrentThreadId());
        return ((jmp_buf *)0);
    }

    // Check for 'first call in new thread context' case where we need to set
    // up new thread data space.
    if (potentialNewThread)
    {
        prev = tp = tidlist;
        while(tp != TIDNULL)        // look for tid in current list
        {
            if (tp->tid == GetCurrentThreadId())
                break;
            prev = tp;
            tp = tp->next;
        }
        if (tp == TIDNULL)      // must be new thread!
        {
            potentialNewThread = FALSE;     // remove search criteria

            tp = (TidListPtr)malloc(sizeof(TidList));   // make new node
            if (tp == TIDNULL)
            {
                fprintf(stderr, "ccpuSimulatePtr: can't malloc space for new thread data\n");
                return((jmp_buf *)0);
            }
            // connect & initialise node
            prev->next = tp;
            tp->tid = GetCurrentThreadId();
            tp->next = TIDNULL;
            //get tls data
            ccpu386foundnewthread();
        }
    }

    simstack = (ThreadSimBufPtr)TlsGetValue(ccpuSimId);
    if (simstack == (ThreadSimBufPtr)0)
    {
        fprintf(stderr, "ccpu386SimulatePtr tid:%#x simid %#x TlsGetValue failed (err:%#x)\n", GetCurrentThreadId(), ccpuSimId, GetLastError());
        return ((jmp_buf *)0);
    }
    
    if (simstack->level >= MAXDEPTH)
    {
        fprintf(stderr, "Stack overflow in ccpu386SimulatePtr()!\n");
        return((jmp_buf *)0);
    }

      /* return pointer to current context and invoke a new CPU level */
      /* can't setjmp here & return otherwise stack unwinds & context lost */

    return(&simstack->sims[simstack->level++]);
}

void ccpu386Unsimulate()
{
    ThreadSimBufPtr simstack;
    extern ISM32 in_C;

    if (ccpuSimId == BADID)
    {
        fprintf(stderr, "ccpu386Unsimulate id:%#x called with Bad Id\n", GetCurrentThreadId());
        return ;
    }
    simstack = (ThreadSimBufPtr)TlsGetValue(ccpuSimId);
    if (simstack == (ThreadSimBufPtr)0)
    {
        fprintf(stderr, "ccpu386Unsimulate tid:%#x simid %#x TlsGetValue failed (err:%#x)\n", GetCurrentThreadId(), ccpuSimId, GetLastError());
        return ;
    }
    
    if (simstack->level == 0)
    {
        fprintf(stderr, "host_unsimulate() - already at base of stack!\n");
    }

    /* Return to previous context */
    in_C = 1;
    simstack->level --;
    longjmp(simstack->sims[simstack->level], 1);
}

   /* somewhere for exceptions to return to */
jmp_buf *ccpu386ThrdExptnPtr()
{
    ThreadSimBufPtr simstack;

    if (ccpuSimId == BADID)
    {
        fprintf(stderr, "ccpu386ThrdExptnPtr id:%#x called with Bad Id\n", GetCurrentThreadId());
        return ;
    }
    simstack = (ThreadSimBufPtr)TlsGetValue(ccpuSimId);
    if (simstack == (ThreadSimBufPtr)0)
    {
        fprintf(stderr, "ccpu386ThrdExptnPtr id:%#x TlsGetValue failed (err:%#x)\n", GetCurrentThreadId(), GetLastError());
        return ;
    }
    
    return(&simstack->excepts[simstack->level - 1]);
}

/* take exception */
void ccpu386GotoThrdExptnPt()
{
    ThreadSimBufPtr simstack;

    if (ccpuSimId == BADID)
    {
        fprintf(stderr, "ccpu386GotoThrdExptnPtr id:%#x called with Bad Id\n", GetCurrentThreadId());
        return;
    }
    simstack = (ThreadSimBufPtr)TlsGetValue(ccpuSimId);
    if (simstack == (ThreadSimBufPtr)0)
    {
        fprintf(stderr, "ccpu386GotoThrdExptnPtr id:%#x TlsGetValue failed (err:%#x)\n", GetCurrentThreadId(), GetLastError());
        return ;
    }
    
    longjmp(simstack->excepts[simstack->level - 1], 1);
}