Add "fast RAM semaphore" support.

Thanks to Mike Kaply <mkaply@us.ibm.com> for the patch.
Bug #125123 r=wtc
This commit is contained in:
seawood%netscape.com 2002-02-16 02:24:56 +00:00
Родитель 98bb38ac3e
Коммит 5aa65e3ac5
3 изменённых файлов: 375 добавлений и 12 удалений

Просмотреть файл

@ -47,6 +47,33 @@
#include <errno.h>
#define USE_RAMSEM
#ifdef USE_RAMSEM
#pragma pack(4)
#pragma pack(2)
typedef struct _RAMSEM
{
ULONG ulTIDPID;
ULONG hevSem;
ULONG cLocks;
USHORT cWaiting;
USHORT cPosts;
} RAMSEM, *PRAMSEM;
typedef struct _CRITICAL_SECTION
{
ULONG ulReserved[4]; /* Same size as RAMSEM */
} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION;
#pragma pack(4)
VOID APIENTRY DeleteCriticalSection(PCRITICAL_SECTION);
VOID APIENTRY EnterCriticalSection(PCRITICAL_SECTION);
VOID APIENTRY InitializeCriticalSection(PCRITICAL_SECTION);
VOID APIENTRY LeaveCriticalSection(PCRITICAL_SECTION);
#endif
#ifdef XP_OS2_EMX
/*
* EMX-specific tweaks:
@ -162,7 +189,11 @@ struct _MDNotified {
};
struct _MDLock {
HMTX mutex; /* this is recursive on NT */
#ifdef USE_RAMSEM
CRITICAL_SECTION mutex; /* this is recursive on NT */
#else
HMTX mutex; /* this is recursive on NT */
#endif
/*
* When notifying cvars, there is no point in actually

Просмотреть файл

@ -48,6 +48,40 @@
#include "primpl.h"
#ifdef USE_RAMSEM
ULONG _Far16 _Pascal Dos16GetInfoSeg(PSEL pselGlobal, PSEL pselLocal);
APIRET _Optlink SemRequest486(PRAMSEM, ULONG);
APIRET _Optlink SemReleasex86(PRAMSEM, ULONG);
typedef struct _LINFOSEG
{
USHORT pidCurrent;
USHORT pidParent;
USHORT prtyCurrent;
USHORT tidCurrent;
USHORT sgCurrent;
UCHAR rfProcStatus;
UCHAR dummy1;
BOOL16 fForeground;
UCHAR typProcess;
UCHAR dummy2;
SEL selEnvironment;
USHORT offCmdLine;
USHORT cbDataSegment;
USHORT cbStack;
USHORT cbHeap;
USHORT hmod;
SEL selDS;
SEL selPack;
SEL selPackShr;
SEL selPackPck;
ULONG ulReserved;
} LINFOSEG;
typedef LINFOSEG FAR *PLINFOSEG;
PLINFOSEG plisCurrent = NULL;
#endif
/*
* AddThreadToCVWaitQueueInternal --
*
@ -163,7 +197,11 @@ md_UnlockAndPostNotifies(
}
/* Release the lock before notifying */
DosReleaseMutexSem(lock->mutex);
#ifdef USE_RAMSEM
SemReleasex86(&lock->mutex, 0);
#else
DosReleaseMutexSem(lock->mutex);
#endif
notified = &post; /* this is where we start */
do {
@ -270,7 +308,11 @@ _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout )
md_UnlockAndPostNotifies(lock, thred, cv);
} else {
AddThreadToCVWaitQueueInternal(thred, cv);
#ifdef USE_RAMSEM
SemReleasex86( &lock->mutex, 0 );
#else
DosReleaseMutexSem(lock->mutex);
#endif
}
/* Wait for notification or timeout; don't really care which */
@ -279,7 +321,11 @@ _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout )
DosResetEventSem(thred->md.blocked_sema, &count);
}
#ifdef USE_RAMSEM
SemRequest486(&(lock->mutex), -1);
#else
DosRequestMutexSem((lock->mutex), SEM_INDEFINITE_WAIT);
#endif
PR_ASSERT(rv == NO_ERROR || rv == ERROR_TIMEOUT);
@ -336,27 +382,70 @@ _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock)
PRStatus
_PR_MD_NEW_LOCK(_MDLock *lock)
{
#ifdef USE_RAMSEM
// It's better if this API traps when pCriticalSect is not a valid
// pointer, because we can't return an error code and if we just return
// the API caller will have nasty bugs that are hard to find.
PRAMSEM pramsem = (PRAMSEM)(&(lock->mutex));
/* First time, set up addresses of processor specific functions
*/
if (plisCurrent == NULL)
{
SEL selGlobal = 0, selLocal = 0;
/* Convert 16 bit global information segment to 32 bit address
* by performing CRMA on the 16 bit address: "shift" operation
* to convert sel to flat, "and" operation to mask the address
* to 32-bit
*/
Dos16GetInfoSeg(&selGlobal, &selLocal);
plisCurrent = (PLINFOSEG)(((ULONG)selLocal << 13) &
(ULONG)0x1fff0000);
}
memset(pramsem, 0, sizeof(pramsem));
DosCreateEventSem(0, &pramsem->hevSem, DC_SEM_SHARED, 0);
lock->notified.length=0;
lock->notified.link=NULL;
return PR_SUCCESS;
#else
DosCreateMutexSem(0, &(lock->mutex), 0, 0);
(lock)->notified.length=0;
(lock)->notified.link=NULL;
return PR_SUCCESS;
#endif
}
void
_PR_MD_FREE_LOCK(_MDLock *lock)
{
#ifdef USE_RAMSEM
DosCloseEventSem(((PRAMSEM)(&(lock->mutex)))->hevSem);
#else
DosCloseMutexSem(lock->mutex);
#endif
}
void _PR_MD_LOCK(_MDLock *lock)
{
#ifdef USE_RAMSEM
SemRequest486(&(lock->mutex), -1);
#else
DosRequestMutexSem(lock->mutex, SEM_INDEFINITE_WAIT);
#endif
}
PRIntn
_PR_MD_TEST_AND_LOCK(_MDLock *lock)
{
#ifdef USE_RAMSEM
SemRequest486(&(lock->mutex), -1);
#else
DosRequestMutexSem(lock->mutex, SEM_INDEFINITE_WAIT);
#endif
return 0;
}
@ -373,7 +462,11 @@ _PR_MD_UNLOCK(_MDLock *lock)
if (0 != lock->notified.length) {
md_UnlockAndPostNotifies(lock, NULL, NULL);
} else {
#ifdef USE_RAMSEM
SemReleasex86( &lock->mutex, 0 );
#else
DosReleaseMutexSem(lock->mutex);
#endif
}
return;
}

Просмотреть файл

@ -30,20 +30,258 @@ COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*-
GPL.
Windows uses inline assembly for their atomic functions, so we have
created an assembly file for VACPP on OS/2
created an assembly file for VACPP on OS/2.
This assembly file also contains an implementation of RAM semaphores.
Notes:
The ulTIDPID element of the RAMSEM structure is overloaded in the 386
implementation to hold the TID:PID in the lower 31 bits and the lock
bit in the high bit
|
page ,132
.486P
.MODEL FLAT, OPTLINK
.STACK
ASSUME CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT, FS:FLAT
.CODE
EXTRN Dos32PostEventSem:PROC
EXTRN Dos32WaitEventSem:PROC
EXTRN Dos32ResetEventSem:PROC
ramsem STRUC
ramsem_ulTIDPID DD ?
ramsem_hevSem DD ?
ramsem_cLocks DD ?
ramsem_cWaiting DW ?
ramsem_cPosts DW ?
ramsem ENDS
ERROR_SEM_TIMEOUT equ 121
ERROR_NOT_OWNER equ 288
SEM_RELEASE_UNOWNED equ 1
SEM_RELEASE_ALL equ 2
TS_LOCKBIT equ 31
DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
EXTRN plisCurrent:DWORD
DATA ENDS
CODE32 SEGMENT DWORD USE32 PUBLIC 'CODE'
PUBLIC SemRequest386
PUBLIC SemRequest486
PUBLIC SemReleasex86
PUBLIC _PR_MD_ATOMIC_SET
PUBLIC _PR_MD_ATOMIC_ADD
PUBLIC _PR_MD_ATOMIC_INCREMENT
PUBLIC _PR_MD_ATOMIC_DECREMENT
;;; RAM Semaphores
;;;---------------------------------------------------------------------------
;;; APIRET _Optlink SemRequest(PRAMSEM pramsem, ULONG ulTimeout);
;;;
;;; Registers:
;;; EAX - packed TID:PID word
;;; ECX - address of RAMSEM structure
;;; EDX - length of timeout in milli-seconds
;;;---------------------------------------------------------------------------
ALIGN 04H
SemRequest386 PROC
mov ecx, eax ; For consistency use ecx
; for PRAMSEM (see 486 imp)
push ebx ; Save ebx (volatile)
mov ebx, dword ptr [plisCurrent]
mov eax, dword ptr [ebx+4] ; Place thread id in high
; word, process id in low
mov ax, word ptr [ebx] ; word
pop ebx ; Restore ebx
req386_test:
push eax
sub eax, (ramsem PTR [ecx]).ramsem_ulTIDPID ; This thread the owner?
shl eax,1 ; Don't compare top bit
pop eax
jz req386_inc_exit ; increment the use count
lock inc (ramsem PTR [ecx]).ramsem_cWaiting ; inc waiting flag
; lock ; Uncomment for SMP
lock bts (ramsem PTR [ecx]).ramsem_ulTIDPID, 31 ; Use the high bit as the
jc req386_sleep ; semaphore
or (ramsem PTR [ecx]).ramsem_ulTIDPID, eax ; Copy the rest of the bits
req386_inc_exit:
lock inc (ramsem PTR [ecx]).ramsem_cLocks
xor eax,eax
req386_exit:
ret
req386_sleep:
push eax ; Save eax (volatile)
push ecx ; Save ecx (volatile)
push edx ; Save edx (volatile)
push edx ; timeout
push (ramsem PTR [ecx]).ramsem_hevSem
call Dos32WaitEventSem
add esp, 8
pop edx ; restore edx
pop ecx ; restore ecx
or eax, eax
je req386_reset ; If no error, reset
pop edx ; junk stored eax
jmp req386_exit ; Exit, timed out
req386_reset:
push ecx ; Save ecx (volatile)
push edx ; Save edx (volatile)
sub esp, 4 ; Use stack space for
push esp ; dummy pulPostCt
push (ramsem PTR [ecx]).ramsem_hevSem
call Dos32ResetEventSem
add esp, 12
pop edx ; restore edx
pop ecx ; restore ecx
pop eax ; restore eax
jmp req386_test ; Retry the semaphore
SemRequest386 ENDP
ALIGN 04H
SemRequest486 PROC
push ebx ; Save ebx (volatile)
mov ecx, eax ; PRAMSEM must be in ecx,
; not eax, for cmpxchg
mov ebx, dword ptr [plisCurrent]
mov eax, dword ptr [ebx+4] ; Place thread id in high
; word, process id in low
mov ax, word ptr [ebx] ; word
mov ebx,eax
req486_test:
xor eax,eax
cmp (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx ; If we own the sem, just
jz req486_inc_exit ; increment the use count
lock inc (ramsem PTR [ecx]).ramsem_cWaiting ; inc waiting flag
; lock ; Uncomment for SMP
DB 0F0h
; cmpxchg (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx
; (byte 3 is the offset of ulProcessThread into the RAMSEM structure)
DB 00Fh
DB 0B1h
DB 019h
jnz req486_sleep
req486_inc_exit:
lock inc (ramsem PTR [ecx]).ramsem_cLocks
req486_exit:
pop ebx ; Restore ebx
ret
req486_sleep:
push ecx ; Save ecx (volatile)
push edx ; Save edx (volatile)
push edx ; timeout
push (ramsem PTR [ecx]).ramsem_hevSem
call Dos32WaitEventSem
add esp, 8
pop edx ; restore edx
pop ecx ; restore ecx
or eax, eax
jne req486_exit ; Exit, if error
push ecx ; Save ecx (volatile)
push edx ; Save edx (volatile)
sub esp, 4 ; Use stack space for
push esp ; dummy pulPostCt
push (ramsem PTR [ecx]).ramsem_hevSem
call Dos32ResetEventSem
add esp, 12
pop edx ; restore edx
pop ecx ; restore ecx
jmp req486_test ; Retry the semaphore
SemRequest486 ENDP
;;;---------------------------------------------------------------------
;;; APIRET _Optlink SemReleasex86(PRAMSEM pramsem, ULONG flFlags);
;;;
;;; Registers:
;;; EAX - address of RAMSEM structure
;;; ECX - temporary variable
;;; EDX - flags
;;;---------------------------------------------------------------------
ALIGN 04H
SemReleasex86 PROC
test edx, SEM_RELEASE_UNOWNED ; If set, don't bother
jnz rel_ownerok ; getting/checking PID/TID
push ebx ; Save ebx (volatile)
mov ebx, dword ptr [plisCurrent]
mov ecx, dword ptr [ebx+4] ; Place thread id in high
; word, process id in low
mov cx, word ptr [ebx] ; word
pop ebx ; Restore ebx
sub ecx, (ramsem PTR [eax]).ramsem_ulTIDPID ; This thread the owner?
shl ecx,1 ; Don't compare top bit
jnz rel_notowner
rel_ownerok:
test edx, SEM_RELEASE_ALL
jnz rel_clear
lock dec (ramsem PTR [eax]).ramsem_cLocks
jnz rel_exit
rel_disown:
mov (ramsem PTR [eax]).ramsem_ulTIDPID, 0
lock inc (ramsem PTR [eax]).ramsem_cPosts
mov cx, (ramsem PTR [eax]).ramsem_cWaiting
cmp (ramsem PTR [eax]).ramsem_cPosts, cx
jne rel_post
rel_exit:
xor eax, eax
ret
rel_clear:
lock mov (ramsem PTR [eax]).ramsem_cLocks,0
jmp rel_disown
rel_notowner:
mov eax, ERROR_NOT_OWNER
ret
rel_post:
mov (ramsem PTR [eax]).ramsem_cPosts, cx
push (ramsem PTR [eax]).ramsem_hevSem
call Dos32PostEventSem
add esp,4
xor eax,eax
ret
SemReleasex86 ENDP
;;; Atomic functions
;;;---------------------------------------------------------------------
;;; PRInt32 _Optlink _PR_MD_ATOMIC_SET(PRInt32* val, PRInt32 newval)
;;;---------------------------------------------------------------------
_PR_MD_ATOMIC_SET PROC OPTLINK EXPORT
lock xchg dword ptr [eax],edx
_PR_MD_ATOMIC_SET proc
lock xchg dword ptr [eax],edx
mov eax, edx;
ret
@ -52,7 +290,7 @@ _PR_MD_ATOMIC_SET endp
;;;---------------------------------------------------------------------
;;; PRInt32 _Optlink _PR_MD_ATOMIC_ADD(PRInt32* ptr, PRInt32 val)
;;;---------------------------------------------------------------------
_PR_MD_ATOMIC_ADD PROC OPTLINK EXPORT
_PR_MD_ATOMIC_ADD proc
mov ecx, edx
lock xadd dword ptr [eax], edx
mov eax, edx
@ -64,7 +302,7 @@ _PR_MD_ATOMIC_ADD endp
;;;---------------------------------------------------------------------
;;; PRInt32 _Optlink _PR_MD_ATOMIC_INCREMENT(PRInt32* val)
;;;---------------------------------------------------------------------
_PR_MD_ATOMIC_INCREMENT PROC OPTLINK EXPORT
_PR_MD_ATOMIC_INCREMENT proc
mov edx, 1
lock xadd dword ptr [eax], edx
mov eax, edx
@ -76,7 +314,7 @@ _PR_MD_ATOMIC_INCREMENT endp
;;;---------------------------------------------------------------------
;;; PRInt32 _Optlink _PR_MD_ATOMIC_DECREMENT(PRInt32* val)
;;;---------------------------------------------------------------------
_PR_MD_ATOMIC_DECREMENT PROC OPTLINK EXPORT
_PR_MD_ATOMIC_DECREMENT proc
mov edx, 0ffffffffh
lock xadd dword ptr [eax], edx
mov eax, edx
@ -85,4 +323,5 @@ _PR_MD_ATOMIC_DECREMENT PROC OPTLINK EXPORT
ret
_PR_MD_ATOMIC_DECREMENT endp
END
CODE32 ENDS
END