netscape-revival
nspr-/src/md_WIN.c
#include <windows.h>
#include <io.h> /* _open() and _close() */
#include <fcntl.h> /* O_RDONLY */
#include <stddef.h> /* offsetof() */
#include <string.h> /* memset() */
#include "prthread.h"
#include "prmon.h"
#include "prprf.h"
#include "mdint.h"
#include "prlog.h"
#ifdef SW_THREADS
#include "swkern.h"
#endif
/* The "main" thread which performed the NSPR initialization. */
PRThread *_pr_primary_thread;
/************************************************************************/
/*
** Machine Dependent routines for thread-stack management:
*/
/************************************************************************/
/* List of free stack virtual memory chunks */
PRCList _pr_free_stacks = PR_INIT_STATIC_CLIST(&_pr_free_stacks);
/*
** Macros for locking the list of freee stack structures...
**
** Since, Win16 is not a preemptive environment, no locking
** is necessary.
*/
#ifdef _WIN32
PRMonitor *_pr_md_lock;
#define CREATE_MD_LOCK() _pr_md_lock = PR_NewNamedMonitor(0, "md-lock");
#define LOCK_MD() PR_EnterMonitor(_pr_md_lock)
#define UNLOCK_MD() PR_ExitMonitor(_pr_md_lock)
#else /* ! _WIN32 */
#define CREATE_MD_LOCK()
#define LOCK_MD()
#define UNLOCK_MD()
#endif /* ! WIN32 */
#define THREAD_STACK_PTR(_qp) \
((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links)))
#ifdef HW_THREADS
/************************************************************************/
/*
** Native threading implementations of:
** _MD_NewStack
** _MD_FreeStack
** _MD_InitializeStack (Native threads only)
*/
/************************************************************************/
/*
** Allocate a stack for a thread.
*/
int _MD_NewStack(PRThread *thread, size_t stackSize)
{
PRCList *qp;
PRThreadStack *ts = 0;
/* Adjust stackSize. Round up to a page boundary */
if (stackSize == 0) {
stackSize = _MD_DEFAULT_STACK_SIZE;
}
stackSize = (stackSize + pr_pageSize - 1) >> pr_pageShift;
stackSize <<= pr_pageShift;
/*
** Find a free thread stack. This searches the list of free'd up
** virtually mapped thread stacks.
*/
LOCK_MD();
qp = _pr_free_stacks.next;
ts = 0;
while (qp != &_pr_free_stacks) {
ts = THREAD_STACK_PTR(qp);
qp = qp->next;
if (ts->flags == 0) {
/* Found a stack that is not in use */
PR_REMOVE_LINK(&ts->links);
ts->links.next = 0;
ts->links.prev = 0;
ts->flags = _PR_THREAD_STACK_BUSY;
break;
}
ts = 0;
}
UNLOCK_MD();
if (!ts) {
/* Make a new thread stack object. */
ts = (PRThreadStack*) calloc(1, sizeof(PRThreadStack));
if (!ts) {
return 0;
}
ts->flags = _PR_THREAD_STACK_BUSY;
}
ts->stackSize = stackSize;
ts->stackTop = 0;
thread->stack = ts;
return 1;
}
/*
** Free a stack for a thread
*/
void _MD_FreeStack(PRThread *thread)
{
PRThreadStack *ts;
ts = thread->stack;
if (!ts) {
return;
}
/* Zap thread->stack to prevent the GC from looking at a dead stack */
thread->stack = 0;
/* place the thread stack back in the free list */
LOCK_MD();
PR_APPEND_LINK(&ts->links, &_pr_free_stacks);
ts->flags = 0;
UNLOCK_MD();
}
/*
** Initialize a stack for a thread
*/
void _MD_InitializeStack(PRThreadStack *ts)
{
if( ts && (ts->stackTop == 0) ) {
/* In Win32 the stacks are NOT allocated from the heap...*/
ts->allocBase = (char *)&ts;
ts->allocSize = ts->stackSize;
/*
** Setup stackTop and stackBottom values.
** On PCs the stack grows "down"
*/
ts->stackTop = ts->allocBase;
ts->stackBottom = ts->allocBase - ts->stackSize;
}
}
#endif /* HW_THREADS */
#ifdef SW_THREADS
/************************************************************************/
/*
** User threading implementations of:
** _MD_NewStack
** _MD_FreeStack
*/
/************************************************************************/
/* How much space to leave between the stacks, at each end */
#define REDZONE (2 << pr_pageShift)
/*
** Allocate a stack for a thread.
*/
int _MD_NewStack(PRThread *thread, size_t stackSize)
{
char *p;
PRThreadStack *ts = 0;
/* Adjust stackSize. Round up to a page boundary */
if (stackSize == 0) {
stackSize = _MD_DEFAULT_STACK_SIZE;
}
stackSize = (size_t)((stackSize + pr_pageSize - 1) >> pr_pageShift);
stackSize <<= pr_pageShift;
/*
** Use malloc to get the stack memory. This is the fallback code used
** on systems which:
**
** (1) don't have a /dev/zero, or
** (2) have a random problem with mmaping.
**
** When we create a stack this way, we can't get a proper redzone so
** we just pad the allocation.
*/
ts = (PRThreadStack*) calloc(1, sizeof(PRThreadStack));
if (!ts) {
return 0;
}
p = malloc(stackSize + 2*REDZONE);
if (!p) {
free(ts);
return 0;
}
ts->allocBase = p;
ts->allocSize = stackSize + 2*REDZONE;
ts->flags = _PR_THREAD_STACK_BUSY;
#ifdef DEBUG
/*
** Fill the redzone memory with a specific pattern so that we can
** check for it.
*/
memset(p, 0xBF, REDZONE);
memset(p + REDZONE + stackSize, 0xBF, REDZONE);
#endif
PR_LOG(THREAD, warn,
("malloc thread stack: base=0x%x limit=0x%x bottom=0x%x top=0x%x",
ts->allocBase, ts->allocBase + ts->allocSize - 1,
ts->allocBase + REDZONE, ts->allocBase + REDZONE + stackSize - 1));
/*
** Setup stackTop and stackBottom values. Note that we are very
** careful to use the stackSize variable, NOT the ts->allocSize
** variable. The ts->allocSize variable represents the allocated size
** of the stack's VIRTUAL region, not the amount in use at the
** moment.
*/
ts->stackSize = stackSize;
#ifdef HAVE_STACK_GROWING_UP
ts->stackTop = ts->allocBase + REDZONE;
ts->stackBottom = ts->stackTop + stackSize;
#else
ts->stackBottom = ts->allocBase + REDZONE;
ts->stackTop = ts->stackBottom + stackSize;
#endif
#if !defined(_WIN32)
ts->SP = ts->stackTop;
#endif
#if defined(DEBUG)
/*
** Fill stack memory with something that turns into an illegal
** pointer value. This will sometimes find runtime references to
** uninitialized pointers. We don't do this for solaris because we
** can use purify instead.
*/
if (ts->stackBottom < ts->stackTop) {
memset(ts->stackBottom, 0xfe, stackSize);
} else {
memset(ts->stackTop, 0xfe, stackSize);
}
#endif
thread->stack = ts;
return 1;
}
/*
** Free a stack for a thread
*/
void _MD_FreeStack(PRThread *thread)
{
PRThreadStack *ts;
ts = thread->stack;
if (!ts) {
return;
}
/* Zap thread->stack to prevent the GC from looking at a dead stack */
thread->stack = 0;
free(ts->allocBase);
ts->allocBase = 0;
free(ts);
}
#endif /* SW_THREADS */
/************************************************************************/
/*
** Machine dependent initialization routines:
** _MD_InitOS
** _MD_StartClock
*/
/************************************************************************/
extern void __md_InitOS(int);
void _MD_InitOS(int when)
{
if (when == _MD_INIT_AT_START) {
CREATE_MD_LOCK();
/* Register the windows message for NSPR Event notification */
_pr_PostEventMsgId = RegisterWindowMessage("NSPR_PostEvent");
}
else if (when == _MD_INIT_READY) {
_pr_primary_thread = PR_CurrentThread();
}
/*
** Perform any Win16/Win32 only initializations...
*/
__md_InitOS(when);
}
/************************************************************************/
/*
** Machine dependent timer routines:
** _MD_StartClock
*/
/************************************************************************/
#ifdef SW_THREADS
extern void _PR_ClockInterruptHandler(void);
extern void CALLBACK _loadds TickTimerProc(HWND,UINT,UINT,DWORD);
static UINT TimerId;
void _MD_StartClock(void)
{
/* Initialize a Windows timer */
TimerId = SetTimer(NULL, 0, 100, TickTimerProc);
/*
** XXX: How do we fail if a timer is unavailable ??
*/
if( TimerId == 0 ) {
exit(1);
}
}
void _PR_Pause(void)
{
MSG msg;
/*
** Call PeekMessage(...) to allow other Tasks to run...
** (This is important for Win16 only)
*/
(void) PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
PR_Yield();
}
/*
** Timer callback routine...
**
** This routine is called for every WM_TIMER message.
*/
static int OldPriorityOfPrimaryThread = -1;
static int TimeSlicesOnNonPrimaryThread = 0;
void CALLBACK _loadds TickTimerProc(HWND hWnd, UINT msg, UINT uTimerId, DWORD time)
{
/* Tell nspr that a clock interrupt occured. */
_PR_ClockInterruptHandler();
}
#endif /* SW_THREADS */
#ifdef HW_THREADS
/*
** The native threading implementation does NOT require timers to
** perform the thread scheduling...
*/
void _MD_StartClock(void) {}
void _PR_Pause(void)
{
PR_Yield();
}
#endif /* HW_THREADS */
/************************************************************************/
/*
** Machine dependent routines for returning system information:
** _MD_GetHostname
** _MD_GetOSName
** _MD_GetOSVersion
** _MD_GetArchitecture
*/
/************************************************************************/
long _MD_GetHostname(char *buf, long count)
{
long i = 0;
if( gethostname(buf, (int)count) == 0 ) {
while( buf[i] && i < count ) {
if( buf[i] == '.' ) {
buf[i] = '\0';
break;
}
i += 1;
}
}
return i;
}
long _MD_GetOSName(char *buf, long count)
{
long len = 0;
#ifdef _WIN32
char *name;
OSVERSIONINFO info;
name = NULL;
info.dwOSVersionInfoSize = sizeof(info);
if( GetVersionEx( &info ) ) {
switch( info.dwPlatformId ) {
case VER_PLATFORM_WIN32s:
name = "Win32s";
break;
case VER_PLATFORM_WIN32_WINDOWS:
name = "Windows 95";
break;
case VER_PLATFORM_WIN32_NT:
name = "Windows NT";
break;
}
if( name ) {
len = PR_snprintf(buf, count, name);
}
}
#else /* ! _WIN32 */
len = PR_snprintf(buf, (size_t)count, "16-bit Windows");
#endif /* !_WIN32 */
return len;
}
long _MD_GetOSVersion(char *buf, long count)
{
long len = 0;
#ifdef _WIN32
char *version;
OSVERSIONINFO info;
version = NULL;
info.dwOSVersionInfoSize = sizeof(info);
if( GetVersionEx( &info ) ) {
len = PR_snprintf(buf, count, "%d.%d", info.dwMajorVersion,
info.dwMinorVersion);
}
#else /* !_WIN32 */
len = PR_snprintf(buf, (size_t)count, "3.1");
#endif /* !_WIN32 */
return len;
}
long _MD_GetArchitecture(char *buf, long count)
{
long len = 0;
#ifdef _WIN32
SYSTEM_INFO info;
char *type = "";
GetSystemInfo( &info );
switch( info.wProcessorArchitecture ) {
case PROCESSOR_ARCHITECTURE_INTEL:
/*
** Contrary to the Win32 documentation the wProcessorLevel field of
** the SYSTEM_INFO struct is NOT initialized in Windows 95. Therefore,
** we must use the "obsolete" dwProcessorType field instead.
*/
switch( info.dwProcessorType ) {
case PROCESSOR_INTEL_386: type = "80386" ; break;
case PROCESSOR_INTEL_486: type = "80486" ; break;
case PROCESSOR_INTEL_PENTIUM: type = "Pentium"; break;
}
break;
case PROCESSOR_ARCHITECTURE_MIPS:
type = "MIPS";
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
type = "Alpha";
break;
case PROCESSOR_ARCHITECTURE_PPC:
type = "PPC";
break;
}
if( type ) {
len = PR_snprintf(buf, count, type);
}
#else /* !_WIN32 */
len = PR_snprintf(buf, (size_t)count, "Intel");
#endif /* !_WIN32 */
return len;
}