Milán Major

netscape-revival

1 branch
Code

nspr-/src/os_WIN.c

#include <windows.h>
#include <prtypes.h>		/* defines prword_t which is needed by mdint.h */
#include <prthread.h>
#include "prlog.h"          /* PR_ASSERT()                                 */
#include <stddef.h>         /* defines size_t which is needed by mdint.h   */
#include "mdint.h"
#include <setjmp.h>
#include "prgc.h"
#include "gcint.h"

/*
** Home the GC registers for the given thread into it's thread
** context area.
*/
#ifdef SW_THREADS
prword_t *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
{
    if (isCurrent) {
        _MD_SAVE_CONTEXT(t);
    }
#ifdef _WIN32
    *np = PR_NUM_GCREGS;
#else   /* !_WIN32 */
    /*
    ** In Win16 because the premption is "cooperative" it can never be the 
    ** case that a register holds the sole reference to an object.  It
    ** will always have been pushed onto the stack before the thread
    ** switch...  So don't bother to scan the registers...
    */
    *np = 0;
#endif  /* !_WIN32 */

    return (prword_t*) CONTEXT(t);
}
#else
prword_t *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) 
{
    CONTEXT context;
    context.ContextFlags = CONTEXT_INTEGER;

    if (GetThreadContext(t->handle, &context)) {
        t->context[0] = context.Eax;
        t->context[1] = context.Ebx;
        t->context[2] = context.Ecx;
        t->context[3] = context.Edx;
        t->context[4] = context.Esi;
        t->context[5] = context.Edi;
        t->context[6] = context.Esp;
        t->context[7] = context.Ebp;
        *np = PR_NUM_GCREGS;
    } else {
        PR_ASSERT(0);/* XXX */
    }
    return (prword_t*) t->context;
}

#endif /* SW_THREADS */


#if !defined(_WIN32)
#include "swkern.h"

extern void
PRWin16ScanCStack(PRThread *t, prword_t *low, prword_t *high)
{
	prword_t scan;
	prword_t limit;
	
    void (*processRoot)(void GCPTR *p, int32 count);

    processRoot = _pr_gcData.processRoot;
    
    scan = (prword_t) low;
    limit = (prword_t) high;
	while (scan < limit) {
		prword_t *test;

		test = *((prword_t **)scan);
		
		if (GC_IN_HEAP(&_pr_gcData, test)) {
			PR_PROCESS_ROOT_LOG(("Thread %s: sp=%p", t->name, scan));
			(*processRoot)(test, 1);
		} 
		scan += sizeof(uint16);		
	}

}

extern PRThread *_pr_primary_thread;
static int OldPriorityOfPrimaryThread   = -1;
static int TimeSlicesOnNonPrimaryThread =  0;

/*
** Resume execution of the thread t.
*/
void _MD_RESTORE_CONTEXT(PRThread *t)
{
    /*
    ** These variables cannot be on the stack since they are used during the 
    ** stack swapping...
    */
    static char *pTopOfStack;
    static char *pThreadStack;
    static char *pTaskStack;

    /*	
    **	This is a good opportunity to make sure that the main
    **	mozilla thread actually gets some time.  If interrupts
    **	are on, then we know it is safe to check if the main
    **	thread is being starved.  If moz has not been scheduled
    **	for a long time, then then temporarily bump the fe priority 
    **	up so that it gets to run at least one. 
    */	
    if (_pr_primary_thread == t) {
        if (OldPriorityOfPrimaryThread != -1) {
            PR_SetThreadPriority(_pr_primary_thread, OldPriorityOfPrimaryThread);
            OldPriorityOfPrimaryThread = -1;
        }
        TimeSlicesOnNonPrimaryThread = 0;
    } else {
        TimeSlicesOnNonPrimaryThread++;
    }

    if ((TimeSlicesOnNonPrimaryThread >= 20) && (OldPriorityOfPrimaryThread == -1)) {
        OldPriorityOfPrimaryThread = PR_GetThreadPriority(_pr_primary_thread);
        PR_SetThreadPriority(_pr_primary_thread, 31);
        TimeSlicesOnNonPrimaryThread = 0;
    }

    /*
    ** Save the Task Stack into the "cached thread stack" of the current thread
    */
    pTaskStack   = _pr_top_of_task_stack;
    pTopOfStack  = (char *) &t;
    pThreadStack = (char *)_pr_current_thread->stack->stackTop;

    PR_ASSERT( pTaskStack >= pTopOfStack );

    /*
    ** Display the range of the current Task stack and the range
    ** of the cached stack that it is copied to...
    */

    while (pTaskStack >= pTopOfStack) {
        *pThreadStack-- = *pTaskStack--;
    }

    /* Save the amount of the stack that was copied... */
    _pr_current_thread->stack->SP = pThreadStack;

    /* Mark the new thread as the current thread */
    _pr_current_thread = t;

    /*
    ** Now copy the "cached thread stack" of the new thread into the Task Stack
    **
    ** REMEMBER:
    **    After the stack has been copied, ALL local variables in this function
    **    are invalid !!
    */
    pTaskStack   = _pr_top_of_task_stack;
    pTopOfStack  = t->stack->SP;
    pThreadStack = t->stack->stackTop;

    PR_ASSERT( pThreadStack >= pTopOfStack );

    while (pThreadStack >= pTopOfStack) {
        *pTaskStack-- = *pThreadStack--;
    }
    /* 
    ** IMPORTANT:
    ** ----------
    ** SS:SP is now invalid :-( This means that all local variables and
    ** function arguments are invalid and NO function calls can be
    ** made !!! We must fix up SS:SP so that function calls can safely
    ** be made...
    */

    __asm {
        mov     ax, WORD PTR [pTopOfStack + 2]
        mov     ss, ax
        mov     ax, WORD PTR [pTopOfStack]
        mov     sp, ax
    }

    PR_LOG(SCHED, warn, ("Scheduled"));

    errno = (_pr_current_thread)->errcode;
    Throw(CONTEXT(_pr_current_thread), 1);
}

#endif /* !_WIN32 */