Added BeOS files contributed by Matthew Zahorik <maz@albany.net>.

git-svn-id: svn://10.0.0.236/trunk@18533 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
wtc%netscape.com 1999-01-25 23:52:00 +00:00
parent 20cff3e357
commit 5e0ff19bc7
24 changed files with 5465 additions and 0 deletions

View File

@ -0,0 +1,31 @@
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "MPL"); you may not use this file except in
# compliance with the MPL. You may obtain a copy of the MPL at
# http://www.mozilla.org/MPL/
#
# Software distributed under the MPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
# for the specific language governing rights and limitations under the
# MPL.
#
#! gmake
MOD_DEPTH = ../../..
include $(MOD_DEPTH)/config/config.mk
include bsrcs.mk
CSRCS += $(BTCSRCS)
TARGETS = $(OBJS)
INCLUDES = -I$(DIST)/include/private -I$(DIST)/include
include $(MOD_DEPTH)/config/rules.mk
export:: $(TARGETS)
install:: export

View File

@ -0,0 +1,25 @@
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "MPL"); you may not use this file except in
# compliance with the MPL. You may obtain a copy of the MPL at
# http://www.mozilla.org/MPL/
#
# Software distributed under the MPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
# for the specific language governing rights and limitations under the
# MPL.
#
# this file lists the source files to be compiled (used in Makefile) and
# then enumerated as object files (in objs.mk) for inclusion in the NSPR
# shared library
BTCSRCS = \
btthread.c \
btlocks.c \
btcvar.c \
btmon.c \
btsem.c \
btcmon.c \
btmisc.c \
$(NULL)

View File

@ -0,0 +1,405 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include <kernel/OS.h>
#include "primpl.h"
/*
** Most of this is ripped out of ../threads/prcmon.c
*/
PRLock *_pr_mcacheLock;
#define _PR_NEW_LOCK_MCACHE() (_pr_mcacheLock = PR_NewLock())
#define _PR_LOCK_MCACHE() PR_Lock(_pr_mcacheLock)
#define _PR_UNLOCK_MCACHE() PR_Unlock(_pr_mcacheLock)
typedef struct MonitorCacheEntryStr MonitorCacheEntry;
struct MonitorCacheEntryStr {
MonitorCacheEntry* next;
void* address;
PRMonitor* mon;
long cacheEntryCount;
};
static PRUint32 hash_mask;
static PRUintn num_hash_buckets;
static PRUintn num_hash_buckets_log2;
static MonitorCacheEntry **hash_buckets;
static MonitorCacheEntry *free_entries;
static PRUintn num_free_entries;
static PRBool expanding;
int _pr_mcache_ready;
#define HASH(address) \
((PRUint32) ( ((PRUptrdiff)(address) >> 2) ^ \
((PRUptrdiff)(address) >> 10) ) \
& hash_mask)
/*
** Expand the monitor cache. This grows the hash buckets and allocates a
** new chunk of cache entries and throws them on the free list. We keep
** as many hash buckets as there are entries.
**
** Because we call malloc and malloc may need the monitor cache, we must
** ensure that there are several free monitor cache entries available for
** malloc to get. FREE_THRESHOLD is used to prevent monitor cache
** starvation during monitor cache expansion.
*/
#define FREE_THRESHOLD 5
static PRStatus ExpandMonitorCache(PRUintn new_size_log2)
{
MonitorCacheEntry **old_hash_buckets, *p;
PRUintn i, entries, old_num_hash_buckets, added;
MonitorCacheEntry **new_hash_buckets, *new_entries;
entries = 1L << new_size_log2;
/*
** Expand the monitor-cache-entry free list
*/
new_entries = (MonitorCacheEntry*)PR_CALLOC(
entries * sizeof(MonitorCacheEntry));
if (NULL == new_entries) return PR_FAILURE;
/*
** Allocate system monitors for the new monitor cache entries. If we
** run out of system monitors, break out of the loop.
*/
for (i = 0, added = 0, p = new_entries; i < entries; i++, p++, added++)
{
p->mon = PR_NewMonitor();
if (!p->mon) break;
}
if (added != entries)
{
if (added == 0)
{
/* Totally out of system monitors. Lossage abounds */
PR_DELETE(new_entries);
return PR_FAILURE;
}
/*
** We were able to allocate some of the system monitors. Use
** realloc to shrink down the new_entries memory
*/
p = (MonitorCacheEntry*)PR_REALLOC(
new_entries, added * sizeof(MonitorCacheEntry));
if (p == 0)
{
/*
** Total lossage. We just leaked a bunch of system monitors
** all over the floor. This should never ever happen.
*/
PR_ASSERT(p != 0);
return PR_FAILURE;
}
}
/*
** Now that we have allocated all of the system monitors, build up
** the new free list. We can just update the free_list because we own
** the mcache-lock and we aren't calling anyone who might want to use
** it.
*/
for (i = 0, p = new_entries; i < added - 1; i++, p++) p->next = p + 1;
p->next = free_entries;
free_entries = new_entries;
num_free_entries += added;
/* Try to expand the hash table */
new_hash_buckets = (MonitorCacheEntry**)PR_CALLOC(
entries * sizeof(MonitorCacheEntry*));
if (NULL == new_hash_buckets)
{
/*
** Partial lossage. In this situation we don't get any more hash
** buckets, which just means that the table lookups will take
** longer. This is bad, but not fatal
*/
PR_LOG(_pr_cmon_lm, PR_LOG_WARNING,
("unable to grow monitor cache hash buckets"));
return PR_SUCCESS;
}
/*
** Compute new hash mask value. This value is used to mask an address
** until it's bits are in the right spot for indexing into the hash
** table.
*/
hash_mask = entries - 1;
/*
** Expand the hash table. We have to rehash everything in the old
** table into the new table. */
old_hash_buckets = hash_buckets;
old_num_hash_buckets = num_hash_buckets;
for (i = 0; i < old_num_hash_buckets; i++)
{
p = old_hash_buckets[i];
while (p)
{
MonitorCacheEntry *next = p->next;
/* Hash based on new table size, and then put p in the new table
*/
PRUintn hash = HASH(p->address);
p->next = new_hash_buckets[hash];
new_hash_buckets[hash] = p;
p = next;
}
}
/*
** Switch over to new hash table and THEN call free of the old
** table. Since free might re-enter _pr_mcache_lock, things would
** break terribly if it used the old hash table.
*/
hash_buckets = new_hash_buckets;
num_hash_buckets = entries;
num_hash_buckets_log2 = new_size_log2;
PR_DELETE(old_hash_buckets);
PR_LOG(_pr_cmon_lm, PR_LOG_NOTICE,
("expanded monitor cache to %d (buckets %d)",
num_free_entries, entries));
return PR_SUCCESS;
} /* ExpandMonitorCache */
/*
** Lookup a monitor cache entry by address. Return a pointer to the
** pointer to the monitor cache entry on success, null on failure.
*/
static MonitorCacheEntry **LookupMonitorCacheEntry(void *address)
{
PRUintn hash;
MonitorCacheEntry **pp, *p;
hash = HASH(address);
pp = hash_buckets + hash;
while ((p = *pp) != 0) {
if (p->address == address) {
if (p->cacheEntryCount > 0)
return pp;
else
return NULL;
}
pp = &p->next;
}
return NULL;
}
/*
** Try to create a new cached monitor. If it's already in the cache,
** great - return it. Otherwise get a new free cache entry and set it
** up. If the cache free space is getting low, expand the cache.
*/
static PRMonitor *CreateMonitor(void *address)
{
PRUintn hash;
MonitorCacheEntry **pp, *p;
hash = HASH(address);
pp = hash_buckets + hash;
while ((p = *pp) != 0) {
if (p->address == address) goto gotit;
pp = &p->next;
}
/* Expand the monitor cache if we have run out of free slots in the table */
if (num_free_entries < FREE_THRESHOLD)
{
/* Expand monitor cache */
/*
** This function is called with the lock held. So what's the 'expanding' ** boolean all about? Seems a bit redundant.
*/
if (!expanding)
{
PRStatus rv;
expanding = PR_TRUE;
rv = ExpandMonitorCache(num_hash_buckets_log2 + 1);
expanding = PR_FALSE;
if (PR_FAILURE == rv) return NULL;
/* redo the hash because it'll be different now */
hash = HASH(address);
}
else
{
/*
** We are in process of expanding and we need a cache
** monitor. Make sure we have enough!
*/
PR_ASSERT(num_free_entries > 0);
}
}
/* Make a new monitor */ p = free_entries;
free_entries = p->next;
num_free_entries--;
p->address = address;
p->next = hash_buckets[hash];
hash_buckets[hash] = p;
PR_ASSERT(p->cacheEntryCount == 0);
gotit:
p->cacheEntryCount++;
return p->mon;
}
/* this is needed by prinit for some reason */
void
_PR_InitCMon (void)
{
_PR_NEW_LOCK_MCACHE();
ExpandMonitorCache(3);
_pr_mcache_ready = 1;
}
/**
** Like PR_EnterMonitor except use the "address" to find a monitor in the
** monitor cache. If successful, returns the PRMonitor now associated
** with "address". Note that you must PR_CExitMonitor the address to
** release the monitor cache entry (otherwise the monitor cache will fill
** up). This call will return NULL if the monitor cache needs to be
** expanded and the system is out of memory.
*/
PR_IMPLEMENT(PRMonitor*)
PR_CEnterMonitor (void *address)
{
PRMonitor *mon;
_PR_LOCK_MCACHE();
mon = CreateMonitor( address );
_PR_UNLOCK_MCACHE();
if( !mon ) return( NULL );
PR_EnterMonitor( mon );
return( mon );
}
/*
** Like PR_ExitMonitor except use the "address" to find a monitor in the
** monitor cache.
*/
PR_IMPLEMENT(PRStatus)
PR_CExitMonitor (void *address)
{
MonitorCacheEntry **pp, *p;
PRStatus status = PR_SUCCESS;
_PR_LOCK_MCACHE();
pp = LookupMonitorCacheEntry(address);
if (pp != NULL) {
p = *pp;
if (--p->cacheEntryCount == 0) {
/*
** Nobody is using the system monitor. Put it on the cached free
** list. We are safe from somebody trying to use it because we
** have the mcache locked.
*/
p->address = 0; /* defensive move */
*pp = p->next; /* unlink from hash_buckets */
p->next = free_entries; /* link into free list */
free_entries = p;
num_free_entries++; /* count it as free */
}
status = PR_ExitMonitor(p->mon);
} else {
status = PR_FAILURE;
}
_PR_UNLOCK_MCACHE();
return status;
}
/*
** Like PR_Wait except use the "address" to find a monitor in the
** monitor cache.
*/
PR_IMPLEMENT(PRStatus)
PR_CWait (void *address, PRIntervalTime timeout)
{
MonitorCacheEntry **pp;
PRMonitor *mon;
_PR_LOCK_MCACHE();
pp = LookupMonitorCacheEntry(address);
mon = pp ? ((*pp)->mon) : NULL;
_PR_UNLOCK_MCACHE();
if (mon == NULL)
return PR_FAILURE;
else
{
return PR_Wait( mon, timeout );
}
}
/*
** Like PR_Notify except use the "address" to find a monitor in the
** monitor cache.
*/
PR_IMPLEMENT(PRStatus)
PR_CNotify (void *address)
{
MonitorCacheEntry **pp;
PRMonitor *mon;
_PR_LOCK_MCACHE();
pp = LookupMonitorCacheEntry(address);
mon = pp ? ((*pp)->mon) : NULL;
_PR_UNLOCK_MCACHE();
if (mon == NULL)
return PR_FAILURE;
else
{
return PR_Notify(mon);
}
}
/*
** Like PR_NotifyAll except use the "address" to find a monitor in the
** monitor cache.
*/
PR_IMPLEMENT(PRStatus)
PR_CNotifyAll (void *address)
{
MonitorCacheEntry **pp;
PRMonitor *mon;
_PR_LOCK_MCACHE();
pp = LookupMonitorCacheEntry(address);
mon = pp ? ((*pp)->mon) : NULL;
_PR_UNLOCK_MCACHE();
if (mon == NULL)
return PR_FAILURE;
else
{
return PR_NotifyAll(mon);
}
}

View File

@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include <kernel/OS.h>
#include "primpl.h"
/*
** Create a new condition variable.
**
** "lock" is the lock used to protect the condition variable.
**
** Condition variables are synchronization objects that threads can use
** to wait for some condition to occur.
**
** This may fail if memory is tight or if some operating system resource
** is low. In such cases, a NULL will be returned.
*/
PR_IMPLEMENT(PRCondVar*)
PR_NewCondVar (PRLock *lock)
{
PRCondVar *cv = PR_NEW( PRCondVar );
PR_ASSERT( NULL != lock );
if( NULL != cv )
{
cv->lock = lock;
PR_ASSERT((cv->isem = create_sem( 1, "nspr_sem")) >= B_NO_ERROR );
}
return cv;
} /* PR_NewCondVar */
/*
** Destroy a condition variable. There must be no thread
** waiting on the condvar. The caller is responsible for guaranteeing
** that the condvar is no longer in use.
**
*/
PR_IMPLEMENT(void)
PR_DestroyCondVar (PRCondVar *cvar)
{
PR_ASSERT( delete_sem( cvar->isem ) == B_NO_ERROR );
PR_DELETE( cvar );
}
/*
** The thread that waits on a condition is blocked in a "waiting on
** condition" state until another thread notifies the condition or a
** caller specified amount of time expires. The lock associated with
** the condition variable will be released, which must have be held
** prior to the call to wait.
**
** Logically a notified thread is moved from the "waiting on condition"
** state and made "ready." When scheduled, it will attempt to reacquire
** the lock that it held when wait was called.
**
** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and
** PR_INTERVAL_NO_WAIT. The former value requires that a condition be
** notified (or the thread interrupted) before it will resume from the
** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect
** is to release the lock, possibly causing a rescheduling within the
** runtime, then immediately attempting to reacquire the lock and resume.
**
** Any other value for timeout will cause the thread to be rescheduled
** either due to explicit notification or an expired interval. The latter
** must be determined by treating time as one part of the monitored data
** being protected by the lock and tested explicitly for an expired
** interval.
**
** Returns PR_FAILURE if the caller has not locked the lock associated
** with the condition variable or the thread was interrupted (PR_Interrupt()).
** The particular reason can be extracted with PR_GetError().
*/
PR_IMPLEMENT(PRStatus)
PR_WaitCondVar (PRCondVar *cvar, PRIntervalTime timeout)
{
status_t result;
/*
** This is an entirely stupid bug, but... If you call
** acquire_sem_etc with a timeout of exactly 1,000,000 microseconds
** it returns immediately with B_NO_ERROR. 1,000,010 microseconds
** returns as expected. Running BeOS/Intel R3.1 at this time.
** Forwarded to Be, Inc. for resolution, Bug ID 980624-225956
**
** Update: Be couldn't reproduce it, but removing timeout++ still
** exhibits the problem on BeOS/Intel R4 and BeOS/PPC R4.
*/
timeout++;
PR_Unlock( cvar->lock );
if( PR_INTERVAL_NO_WAIT != timeout )
{
if( PR_INTERVAL_NO_TIMEOUT == timeout )
{
if( acquire_sem( cvar->isem ) != B_NO_ERROR ) return PR_FAILURE;
} else
{
result = acquire_sem_etc( cvar->isem, 1, B_TIMEOUT, PR_IntervalToMicroseconds( timeout ) );
if( result != B_NO_ERROR && result != B_TIMED_OUT )
return PR_FAILURE;
}
}
PR_Lock( cvar->lock );
return PR_SUCCESS;
}
/*
** Notify ONE thread that is currently waiting on 'cvar'. Which thread is
** dependent on the implementation of the runtime. Common sense would dictate
** that all threads waiting on a single condition have identical semantics,
** therefore which one gets notified is not significant.
**
** The calling thead must hold the lock that protects the condition, as
** well as the invariants that are tightly bound to the condition, when
** notify is called.
**
** Returns PR_FAILURE if the caller has not locked the lock associated
** with the condition variable.
*/
PR_IMPLEMENT(PRStatus)
PR_NotifyCondVar (PRCondVar *cvar)
{
if( release_sem( cvar->isem ) != B_NO_ERROR ) return PR_FAILURE;
return PR_SUCCESS;
}
/*
** Notify all of the threads waiting on the condition variable. The order
** that the threads are notified is indeterminant. The lock that protects
** the condition must be held.
**
** Returns PR_FAILURE if the caller has not locked the lock associated
** with the condition variable.
*/
PR_IMPLEMENT(PRStatus)
PR_NotifyAllCondVar (PRCondVar *cvar)
{
sem_info semInfo;
if( get_sem_info( cvar->isem, &semInfo ) != B_NO_ERROR )
return PR_FAILURE;
if( release_sem_etc( cvar->isem, semInfo.count, 0 ) != B_NO_ERROR )
return PR_FAILURE;
}

View File

@ -0,0 +1,89 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
/*
** File: btlocks.c
** Description: Implemenation for thread locks using bthreads
** Exports: prlock.h
*/
#include "primpl.h"
#include <string.h>
#include <sys/time.h>
void
_PR_InitLocks (void)
{
}
PR_IMPLEMENT(PRLock*)
PR_NewLock (void)
{
PRLock *lock;
status_t semresult;
if (!_pr_initialized) _PR_ImplicitInitialization();
lock = PR_NEWZAP(PRLock);
if (lock != NULL) {
lock->benaphoreCount = 0;
lock->semaphoreID = create_sem( 0, "nsprLockSem" );
if( lock->semaphoreID < B_NO_ERROR ) {
PR_DELETE( lock );
lock = NULL;
}
}
return lock;
}
PR_IMPLEMENT(void)
PR_DestroyLock (PRLock* lock)
{
PR_ASSERT(NULL != lock);
PR_ASSERT(delete_sem(lock->semaphoreID) == B_NO_ERROR);
PR_DELETE(lock);
}
PR_IMPLEMENT(void)
PR_Lock (PRLock* lock)
{
PR_ASSERT(lock != NULL);
if( atomic_add( &lock->benaphoreCount, 1 ) > 0 ) {
if( acquire_sem(lock->semaphoreID ) != B_NO_ERROR ) {
atomic_add( &lock->benaphoreCount, -1 );
return;
}
}
lock->owner = find_thread( NULL );
}
PR_IMPLEMENT(PRStatus)
PR_Unlock (PRLock* lock)
{
PR_ASSERT(lock != NULL);
lock->owner = NULL;
if( atomic_add( &lock->benaphoreCount, -1 ) > 1 ) {
release_sem( lock->semaphoreID );
}
return PR_SUCCESS;
}

View File

@ -0,0 +1,80 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
#include <stdio.h>
// void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")}
// void _MD_StartInterrupts(void) {PT_LOG("_MD_StartInterrupts")}
/* this is a total hack.. */
struct protoent* getprotobyname(const char* name)
{
return 0;
}
struct protoent* getprotobynumber(int number)
{
return 0;
}
/* this is needed by prinit for some reason */
void
_PR_InitStacks (void)
{
}
/* this is needed by prinit for some reason */
void
_PR_InitTPD (void)
{
}
/*
** Create extra virtual processor threads. Generally used with MP systems.
*/
PR_IMPLEMENT(void)
PR_SetConcurrency (PRUintn numCPUs)
{
}
/*
** Set thread recycle mode to on (1) or off (0)
*/
PR_IMPLEMENT(void)
PR_SetThreadRecycleMode (PRUint32 flag)
{
}
/*
** Get context registers, return with error for now.
*/
PR_IMPLEMENT(PRWord *)
_MD_HomeGCRegisters( PRThread *t, int isCurrent, int *np )
{
return 0;
}
PR_IMPLEMENT(void *)
PR_GetSP( PRThread *t )
{
return 0;
}
PR_IMPLEMENT(PRStatus)
PR_EnumerateThreads( PREnumerator func, void *arg )
{
return PR_FAILURE;
}

View File

@ -0,0 +1,192 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include <kernel/OS.h>
#include "primpl.h"
/*
** Create a new monitor. Monitors are re-entrant locks with a single built-in
** condition variable.
**
** This may fail if memory is tight or if some operating system resource
** is low.
*/
PR_IMPLEMENT(PRMonitor*)
PR_NewMonitor (void)
{
PRMonitor *mon;
PRCondVar *cvar;
PRLock *lock;
mon = PR_NEWZAP( PRMonitor );
if( mon )
{
lock = PR_NewLock();
if( !lock )
{
PR_DELETE( mon );
return( 0 );
}
cvar = PR_NewCondVar( lock );
if( !cvar )
{
PR_DestroyLock( lock );
PR_DELETE( mon );
return( 0 );
}
mon->cvar = cvar;
mon->name = NULL;
}
return( mon );
}
PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
{
PRMonitor* mon = PR_NewMonitor();
mon->name = name;
return mon;
}
/*
** Destroy a monitor. The caller is responsible for guaranteeing that the
** monitor is no longer in use. There must be no thread waiting on the
** monitor's condition variable and that the lock is not held.
**
*/
PR_IMPLEMENT(void)
PR_DestroyMonitor (PRMonitor *mon)
{
PR_DestroyLock( mon->cvar->lock );
PR_DestroyCondVar( mon->cvar );
PR_DELETE( mon );
}
/*
** Enter the lock associated with the monitor. If the calling thread currently
** is in the monitor, the call to enter will silently succeed. In either case,
** it will increment the entry count by one.
*/
PR_IMPLEMENT(void)
PR_EnterMonitor (PRMonitor *mon)
{
if( mon->cvar->lock->owner == find_thread( NULL ) )
{
mon->entryCount++;
} else
{
PR_Lock( mon->cvar->lock );
mon->entryCount = 1;
}
}
/*
** Decrement the entry count associated with the monitor. If the decremented
** entry count is zero, the monitor is exited. Returns PR_FAILURE if the
** calling thread has not entered the monitor.
*/
PR_IMPLEMENT(PRStatus)
PR_ExitMonitor (PRMonitor *mon)
{
if( mon->cvar->lock->owner != find_thread( NULL ) )
{
return( PR_FAILURE );
}
if( --mon->entryCount == 0 )
{
return( PR_Unlock( mon->cvar->lock ) );
}
return( PR_SUCCESS );
}
/*
** Wait for a notify on the monitor's condition variable. Sleep for "ticks"
** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is
** indefinite).
**
** While the thread is waiting it exits the monitor (as if it called
** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When
** the wait has finished the thread regains control of the monitors lock
** with the same entry count as before the wait began.
**
** The thread waiting on the monitor will be resumed when the monitor is
** notified (assuming the thread is the next in line to receive the
** notify) or when the "ticks" timeout elapses.
**
** Returns PR_FAILURE if the caller has not entered the monitor.
*/
PR_IMPLEMENT(PRStatus)
PR_Wait (PRMonitor *mon, PRIntervalTime ticks)
{
PRUint32 entryCount;
PRUintn status;
PRThread *meThread;
thread_id me = find_thread( NULL );
meThread = PR_GetCurrentThread();
if( mon->cvar->lock->owner != me ) return( PR_FAILURE );
entryCount = mon->entryCount;
mon->entryCount = 0;
status = PR_WaitCondVar( mon->cvar, ticks );
mon->entryCount = entryCount;
return( status );
}
/*
** Notify a thread waiting on the monitor's condition variable. If a thread
** is waiting on the condition variable (using PR_Wait) then it is awakened
** and attempts to reenter the monitor.
*/
PR_IMPLEMENT(PRStatus)
PR_Notify (PRMonitor *mon)
{
if( mon->cvar->lock->owner != find_thread( NULL ) )
{
return( PR_FAILURE );
}
PR_NotifyCondVar( mon->cvar );
return( PR_SUCCESS );
}
/*
** Notify all of the threads waiting on the monitor's condition variable.
** All of threads waiting on the condition are scheduled to reenter the
** monitor.
*/
PR_IMPLEMENT(PRStatus)
PR_NotifyAll (PRMonitor *mon)
{
if( mon->cvar->lock->owner != find_thread( NULL ) )
{
return( PR_FAILURE );
}
PR_NotifyAllCondVar( mon->cvar );
return( PR_SUCCESS );
}
PR_IMPLEMENT(PRIntn)
PR_GetMonitorEntryCount(PRMonitor *mon)
{
return( mon->entryCount );
}

View File

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include <kernel/OS.h>
#include "primpl.h"
/*
** Create a new semaphore object.
*/
PR_IMPLEMENT(PRSemaphore*)
PR_NewSem (PRUintn value)
{
PRSemaphore *semaphore;
if (!_pr_initialized) _PR_ImplicitInitialization();
semaphore = PR_NEWZAP(PRSemaphore);
if (NULL != semaphore) {
if ((semaphore->sem = create_sem(value, "nspr_sem")) < B_NO_ERROR)
return NULL;
else
return semaphore;
}
return NULL;
}
/*
** Destroy the given semaphore object.
**
*/
PR_IMPLEMENT(void)
PR_DestroySem (PRSemaphore *sem)
{
PR_ASSERT(sem != NULL);
PR_ASSERT(delete_sem(sem->sem) == B_NO_ERROR);
PR_DELETE(sem);
}
/*
** Wait on a Semaphore.
**
** This routine allows a calling thread to wait or proceed depending upon
** the state of the semahore sem. The thread can proceed only if the
** counter value of the semaphore sem is currently greater than 0. If the
** value of semaphore sem is positive, it is decremented by one and the
** routine returns immediately allowing the calling thread to continue. If
** the value of semaphore sem is 0, the calling thread blocks awaiting the
** semaphore to be released by another thread.
**
** This routine can return PR_PENDING_INTERRUPT if the waiting thread
** has been interrupted.
*/
PR_IMPLEMENT(PRStatus)
PR_WaitSem (PRSemaphore *sem)
{
PR_ASSERT(sem != NULL);
if (acquire_sem(sem->sem) == B_NO_ERROR)
return PR_SUCCESS;
else
return PR_FAILURE;
}
/*
** This routine increments the counter value of the semaphore. If other
** threads are blocked for the semaphore, then the scheduler will
** determine which ONE thread will be unblocked.
*/
PR_IMPLEMENT(void)
PR_PostSem (PRSemaphore *sem)
{
PR_ASSERT(sem != NULL);
PR_ASSERT(release_sem(sem->sem) == B_NO_ERROR);
}
/*
** Returns the value of the semaphore referenced by sem without affecting
** the state of the semaphore. The value represents the semaphore value
** at the time of the call, but may not be the actual value when the
** caller inspects it.
*/
PR_IMPLEMENT(PRUintn)
PR_GetValueSem (PRSemaphore *sem)
{
sem_info info;
PR_ASSERT(sem != NULL);
get_sem_info(sem->sem, &info);
return info.count;
}

View File

@ -0,0 +1,780 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include <kernel/OS.h>
#include "prlog.h"
#include "primpl.h"
#include "prcvar.h"
#include "prpdce.h"
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#define BT_THREAD_PRIMORD 0x01 /* this is the primordial thread */
#define BT_THREAD_SYSTEM 0x02 /* this is a system thread */
struct _BT_Bookeeping
{
PRLock *ml; /* a lock to protect ourselves */
PRCondVar *cv; /* used to signal global things */
PRInt32 threadCount; /* user thred count */
} bt_book = { 0 };
/*
** A structure at the root of the thread private data. Each member of
** the array keys[] points to a hash table based on the thread's ID.
*/
struct _BT_PrivateData
{
PRLock *lock; /* A lock to coordinate access */
struct _BT_PrivateHash *keys[128]; /* Up to 128 keys, pointing to a hash table */
} bt_privateRoot = { 0 };
/*
** A dynamically allocated structure that contains 256 hash buckets that
** contain a linked list of thread IDs. The hash is simply the last 8 bits
** of the thread_id. ( current thread_id & 0x000000FF )
*/
struct _BT_PrivateHash
{
void (PR_CALLBACK *destructor)(void *arg); /* The destructor */
struct _BT_PrivateEntry *next[256]; /* Pointer to the first element in the list */
};
/*
** A dynamically allocated structure that is a member of a linked list of
** thread IDs.
*/
struct _BT_PrivateEntry
{
struct _BT_PrivateEntry *next; /* Pointer to the next thread */
thread_id threadID; /* The BeOS thread ID */
void *data; /* The data */
};
PRUint32 _bt_mapPriority( PRThreadPriority priority );
PR_IMPLEMENT(void *) _bt_getThreadPrivate(PRUintn index);
void
_PR_InitThreads (PRThreadType type, PRThreadPriority priority,
PRUintn maxPTDs)
{
PRThread *primordialThread;
PRLock *tempLock;
PRUintn tempKey;
PRUint32 beThreadPriority;
/*
** Create a NSPR structure for our primordial thread.
*/
primordialThread = PR_NEWZAP(PRThread);
if( NULL == primordialThread )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
/*
** Set the priority to the desired level.
*/
beThreadPriority = _bt_mapPriority( priority );
set_thread_priority( find_thread( NULL ), beThreadPriority );
primordialThread->state |= BT_THREAD_PRIMORD;
primordialThread->priority = priority;
/*
** Initialize the thread tracking data structures
*/
bt_privateRoot.lock = PR_NewLock();
if( NULL == bt_privateRoot.lock )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
/*
** Grab a key. We're guaranteed to be key #0, since we are
** always the first one in.
*/
if( PR_NewThreadPrivateIndex( &tempKey, NULL ) != PR_SUCCESS )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
PR_ASSERT( tempKey == 0 );
/*
** Stuff our new PRThread structure into our thread specific
** slot.
*/
if( PR_SetThreadPrivate( (PRUint8) 0, (void *) primordialThread ) == PR_FAILURE )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
/*
** Allocate some memory to hold our global lock. We never clean it
** up later, but BeOS automatically frees memory when the thread
** dies.
*/
bt_book.ml = PR_NewLock();
if( NULL == bt_book.ml )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
tempLock = PR_NewLock();
if( NULL == tempLock )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
bt_book.cv = PR_NewCondVar( tempLock );
if( NULL == bt_book.cv )
{
PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
return;
}
}
PRUint32
_bt_mapPriority( PRThreadPriority priority )
{
switch( priority )
{
case PR_PRIORITY_LOW: return( B_LOW_PRIORITY );
case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY );
case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
default: return( B_NORMAL_PRIORITY );
}
}
/**
* This is a wrapper that all threads invoke that allows us to set some
* things up prior to a thread's invocation and clean up after a thread has
* exited.
*/
static void*
_bt_root (void* arg)
{
PRThread *thred = (PRThread*)arg;
PRIntn rv;
void *privData;
status_t result;
int i;
struct _BT_PrivateHash *hashTable;
/* Set within the current thread the pointer to our object. This
object will be deleted when the thread termintates. */
PR_ASSERT( PR_SetThreadPrivate( 0, (void *) thred ) == PR_SUCCESS );
thred->startFunc(thred->arg); /* run the dang thing */
/*
** Call the destructor, if available.
*/
PR_Lock( bt_privateRoot.lock );
for( i = 0; i < 128; i++ )
{
hashTable = bt_privateRoot.keys[i];
if( hashTable != NULL )
{
if( hashTable->destructor != NULL )
{
privData = _bt_getThreadPrivate( i );
if( privData != NULL )
{
PR_Unlock( bt_privateRoot.lock );
hashTable->destructor( privData );
PR_Lock( bt_privateRoot.lock );
}
}
}
}
PR_Unlock( bt_privateRoot.lock );
/* decrement our thread counters */
PR_Lock( bt_book.ml );
if (thred->state & BT_THREAD_SYSTEM) {
#if 0
bt_book.system -= 1;
#endif
} else
{
bt_book.threadCount--;
if( 0 == bt_book.threadCount )
{
PR_NotifyAllCondVar(bt_book.cv);
}
}
PR_Unlock( bt_book.ml );
if( thred->md.is_joinable == 1 )
{
/*
** This is a joinable thread. Keep suspending
** until is_joining is set to 1
*/
if( thred->md.is_joining == 0 )
{
suspend_thread( thred->md.tid );
}
}
/* delete the thread object */
PR_DELETE(thred);
PR_ASSERT( PR_SetThreadPrivate( (PRUint8) 0, (void *) NULL ) == PR_SUCCESS );
exit_thread( NULL );
}
PR_IMPLEMENT(PRThread*)
PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg,
PRThreadPriority priority, PRThreadScope scope,
PRThreadState state, PRUint32 stackSize)
{
PRUint32 bePriority;
PRThread* thred = PR_NEWZAP(PRThread);
if (!_pr_initialized) _PR_ImplicitInitialization();
if (thred != NULL) {
thred->arg = arg;
thred->startFunc = start;
thred->priority = priority;
if( state == PR_JOINABLE_THREAD )
{
thred->md.is_joinable = 1;
}
else
{
thred->md.is_joinable = 0;
}
thred->md.is_joining = 0;
/* keep some books */
PR_Lock( bt_book.ml );
if (PR_SYSTEM_THREAD == type) {
thred->state |= BT_THREAD_SYSTEM;
#if 0
bt_book.system += 1;
#endif
} else {
bt_book.threadCount++;
}
PR_Unlock( bt_book.ml );
bePriority = _bt_mapPriority( priority );
thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread",
bePriority, thred);
if (thred->md.tid < B_OK) {
PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid);
PR_DELETE(thred);
thred = NULL;
}
if (resume_thread(thred->md.tid) < B_OK) {
PR_SetError(PR_UNKNOWN_ERROR, 0);
PR_DELETE(thred);
thred = NULL;
}
} else {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
}
return thred;
}
PR_IMPLEMENT(PRStatus)
PR_JoinThread (PRThread* thred)
{
status_t eval, status;
PR_ASSERT(thred != NULL);
if( thred->md.is_joinable != 1 )
{
PR_SetError( PR_UNKNOWN_ERROR, 0 );
return( PR_FAILURE );
}
thred->md.is_joining = 1;
status = wait_for_thread(thred->md.tid, &eval);
if (status < B_NO_ERROR) {
PR_SetError(PR_UNKNOWN_ERROR, status);
return PR_FAILURE;
}
return PR_SUCCESS;
}
PR_IMPLEMENT(PRThread*)
PR_GetCurrentThread ()
{
void* thred;
if (!_pr_initialized) _PR_ImplicitInitialization();
thred = PR_GetThreadPrivate( (PRUint8) 0 );
PR_ASSERT(NULL != thred);
return (PRThread*)thred;
}
PR_IMPLEMENT(PRThreadScope)
PR_GetThreadScope (const PRThread* thred)
{
PR_ASSERT(thred != NULL);
return PR_GLOBAL_THREAD;
}
PR_IMPLEMENT(PRThreadType)
PR_GetThreadType (const PRThread* thred)
{
PR_ASSERT(thred != NULL);
return (thred->state & BT_THREAD_SYSTEM) ?
PR_SYSTEM_THREAD : PR_USER_THREAD;
}
PR_IMPLEMENT(PRThreadState)
PR_GetThreadState (const PRThread* thred)
{
PR_ASSERT(thred != NULL);
return PR_JOINABLE_THREAD;
}
PR_IMPLEMENT(PRThreadPriority)
PR_GetThreadPriority (const PRThread* thred)
{
PR_ASSERT(thred != NULL);
return thred->priority;
} /* PR_GetThreadPriority */
PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred,
PRThreadPriority newPri)
{
PRUint32 bePriority;
PR_ASSERT( thred != NULL );
thred->priority = newPri;
bePriority = _bt_mapPriority( newPri );
set_thread_priority( thred->md.tid, bePriority );
}
PR_IMPLEMENT(PRStatus)
PR_NewThreadPrivateIndex (PRUintn* newIndex,
PRThreadPrivateDTOR destructor)
{
PRUintn index;
struct _BT_PrivateHash *tempPointer;
if (!_pr_initialized) _PR_ImplicitInitialization();
/*
** Grab the lock, or hang until it is free. This is critical code,
** and only one thread at a time should be going through it.
*/
PR_Lock( bt_privateRoot.lock );
/*
** Run through the array of keys, find the first one that's zero.
** Exit if we hit the top of the array.
*/
index = 0;
while( bt_privateRoot.keys[index] != 0 )
{
index++;
if( 128 == index )
{
PR_Unlock( bt_privateRoot.lock );
return( PR_FAILURE );
}
}
/*
** Index has the first available zeroed slot. Allocate a
** _BT_PrivateHash structure, all zeroed. Assuming that goes
** well, return the index.
*/
tempPointer = PR_NEWZAP( struct _BT_PrivateHash );
if( 0 == tempPointer ) {
PR_Unlock( bt_privateRoot.lock );
return( PR_FAILURE );
}
bt_privateRoot.keys[index] = tempPointer;
tempPointer->destructor = destructor;
PR_Unlock( bt_privateRoot.lock );
*newIndex = index;
return( PR_SUCCESS );
}
PR_IMPLEMENT(PRStatus)
PR_SetThreadPrivate (PRUintn index, void* priv)
{
thread_id currentThread;
PRUint8 hashBucket;
void *tempPointer;
struct _BT_PrivateHash *hashTable;
struct _BT_PrivateEntry *currentEntry;
struct _BT_PrivateEntry *previousEntry;
/*
** Sanity checking
*/
if( index < 0 || index > 127 ) return( PR_FAILURE );
/*
** Grab the thread ID for this thread. Assign it to a hash bucket.
*/
currentThread = find_thread( NULL );
hashBucket = currentThread & 0x000000FF;
/*
** Lock out all other threads then grab the proper hash table based
** on the passed index.
*/
PR_Lock( bt_privateRoot.lock );
hashTable = bt_privateRoot.keys[index];
if( 0 == hashTable )
{
PR_Unlock( bt_privateRoot.lock );
return( PR_FAILURE );
}
/*
** Search through the linked list the end is reached or an existing
** entry is found.
*/
currentEntry = hashTable->next[ hashBucket ];
previousEntry = NULL;
while( currentEntry != 0 )
{
if( currentEntry->threadID == currentThread )
{
/*
** Found a structure previously created for this thread.
** Is there a destructor to be called?
*/
if( hashTable->destructor != NULL )
{
if( currentEntry->data != NULL )
{
PR_Unlock( bt_privateRoot.lock );
hashTable->destructor( currentEntry->data );
PR_Lock( bt_privateRoot.lock );
}
}
/*
** If the data was not NULL, and there was a destructor,
** it has already been called. Overwrite the existing
** data and return with success.
*/
currentEntry->data = priv;
PR_Unlock( bt_privateRoot.lock );
return( PR_SUCCESS );
}
previousEntry = currentEntry;
currentEntry = previousEntry->next;
}
/*
** If we're here, we didn't find an entry for this thread. Create
** one and attach it to the end of the list.
*/
currentEntry = PR_NEWZAP( struct _BT_PrivateEntry );
if( 0 == currentEntry )
{
PR_Unlock( bt_privateRoot.lock );
return( PR_FAILURE );
}
currentEntry->threadID = currentThread;
currentEntry->data = priv;
if( 0 == previousEntry )
{
/*
** This is a special case. This is the first entry in the list
** so set the hash table to point to this entry.
*/
hashTable->next[ hashBucket ] = currentEntry;
}
else
{
previousEntry->next = currentEntry;
}
PR_Unlock( bt_privateRoot.lock );
return( PR_SUCCESS );
}
PR_IMPLEMENT(void*)
_bt_getThreadPrivate(PRUintn index)
{
thread_id currentThread;
PRUint8 hashBucket;
void *tempPointer;
struct _BT_PrivateHash *hashTable;
struct _BT_PrivateEntry *currentEntry;
/*
** Sanity checking
*/
if( index < 0 || index > 127 ) return( NULL );
/*
** Grab the thread ID for this thread. Assign it to a hash bucket.
*/
currentThread = find_thread( NULL );
hashBucket = currentThread & 0x000000FF;
/*
** Grab the proper hash table based on the passed index.
*/
hashTable = bt_privateRoot.keys[index];
if( 0 == hashTable )
{
return( NULL );
}
/*
** Search through the linked list the end is reached or an existing
** entry is found.
*/
currentEntry = hashTable->next[ hashBucket ];
while( currentEntry != 0 )
{
if( currentEntry->threadID == currentThread )
{
/*
** Found a structure previously created for this thread.
** Copy out the data, unlock, and return.
*/
tempPointer = currentEntry->data;
return( tempPointer );
}
currentEntry = currentEntry->next;
}
/*
** Ooops, we ran out of entries. This thread isn't listed.
*/
return( NULL );
}
PR_IMPLEMENT(void*)
PR_GetThreadPrivate (PRUintn index)
{
void *returnValue;
PR_Lock( bt_privateRoot.lock );
returnValue = _bt_getThreadPrivate( index );
PR_Unlock( bt_privateRoot.lock );
return( returnValue );
}
PR_IMPLEMENT(PRStatus)
PR_Interrupt (PRThread* thred)
{
PRIntn rv;
PR_ASSERT(thred != NULL);
rv = resume_thread( thred->md.tid );
if( rv == B_BAD_THREAD_STATE )
{
/*
** We have a thread that's not suspended, but is
** blocked. Suspend it THEN resume it. The
** function call that's hanging will return
** B_INTERRUPTED
*/
rv = suspend_thread( thred->md.tid );
if( rv != B_NO_ERROR )
{
PR_SetError( PR_UNKNOWN_ERROR, rv );
return( PR_FAILURE );
}
rv = resume_thread( thred->md.tid );
if( rv != B_NO_ERROR )
{
PR_SetError( PR_UNKNOWN_ERROR, rv );
return( PR_FAILURE );
}
}
if( rv != B_NO_ERROR )
{
PR_SetError( PR_UNKNOWN_ERROR, rv );
return( PR_FAILURE );
}
return( PR_SUCCESS );
}
PR_IMPLEMENT(void)
PR_ClearInterrupt ()
{
}
PR_IMPLEMENT(PRStatus)
PR_Yield ()
{
/* we just sleep for long enough to cause a reschedule (100
microseconds) */
snooze(100);
}
#define BT_MILLION 1000000UL
PR_IMPLEMENT(PRStatus)
PR_Sleep (PRIntervalTime ticks)
{
bigtime_t tps;
status_t status;
if (!_pr_initialized) _PR_ImplicitInitialization();
tps = PR_IntervalToMicroseconds( ticks );
status = snooze(tps);
if (status == B_NO_ERROR) return PR_SUCCESS;
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status);
return PR_FAILURE;
}
PR_IMPLEMENT(PRStatus)
PR_Cleanup ()
{
PRThread *me = PR_CurrentThread();
PR_ASSERT(me->state & BT_THREAD_PRIMORD);
if ((me->state & BT_THREAD_PRIMORD) == 0) {
return PR_FAILURE;
}
PR_Lock( bt_book.ml );
while( bt_book.threadCount > 0 )
{
PR_Unlock( bt_book.ml );
PR_WaitCondVar(bt_book.cv, PR_INTERVAL_NO_TIMEOUT);
PR_Lock( bt_book.ml );
}
PR_Unlock( bt_book.ml );
#if 0
/* I am not sure if it's safe to delete the cv and lock here, since
* there may still be "system" threads around. If this call isn't
* immediately prior to exiting, then there's a problem. */
if (0 == bt_book.system) {
PR_DestroyCondVar(bt_book.cv); bt_book.cv = NULL;
PR_DestroyLock(bt_book.ml); bt_book.ml = NULL;
}
PR_DELETE(me);
#endif
return PR_SUCCESS;
}
PR_IMPLEMENT(void)
PR_ProcessExit (PRIntn status)
{
exit(status);
}

View File

@ -0,0 +1,18 @@
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "MPL"); you may not use this file except in
# compliance with the MPL. You may obtain a copy of the MPL at
# http://www.mozilla.org/MPL/
#
# Software distributed under the MPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
# for the specific language governing rights and limitations under the
# MPL.
#
# This makefile appends to the variable OBJS the bthread object modules
# that will be part of the nspr20 library.
include bthreads/bsrcs.mk
OBJS += $(BTCSRCS:%.c=bthreads/$(OBJDIR)/%.$(OBJ_SUFFIX))

View File

@ -0,0 +1,28 @@
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "MPL"); you may not use this file except in
# compliance with the MPL. You may obtain a copy of the MPL at
# http://www.mozilla.org/MPL/
#
# Software distributed under the MPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
# for the specific language governing rights and limitations under the
# MPL.
#
MOD_DEPTH = ../../../..
include $(MOD_DEPTH)/config/config.mk
include bsrcs.mk
CSRCS += $(MDCSRCS)
TARGETS = $(OBJS)
INCLUDES = -I$(DIST)/include/private -I$(DIST)/include
include $(MOD_DEPTH)/config/rules.mk
export:: $(TARGETS)
install:: export

View File

@ -0,0 +1,31 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
PR_EXTERN(void) _PR_MD_INIT_CPUS();
PR_EXTERN(void) _PR_MD_WAKEUP_CPUS();
PR_EXTERN(void) _PR_MD_START_INTERRUPTS(void);
PR_EXTERN(void) _PR_MD_STOP_INTERRUPTS(void);
PR_EXTERN(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void);
PR_EXTERN(void) _PR_MD_BLOCK_CLOCK_INTERRUPTS(void);
PR_EXTERN(void) _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(void);
PR_EXTERN(void) _PR_MD_CLOCK_INTERRUPT(void);
PR_EXTERN(void) _PR_MD_INIT_STACK(PRThreadStack *ts, PRIntn redzone);
PR_EXTERN(void) _PR_MD_CLEAR_STACK(PRThreadStack* ts);
PR_EXTERN(PRInt32) _PR_MD_GET_INTSOFF(void);
PR_EXTERN(void) _PR_MD_SET_INTSOFF(PRInt32 _val);
PR_EXTERN(_PRCPU*) _PR_MD_CURRENT_CPU(void);
PR_EXTERN(void) _PR_MD_SET_CURRENT_CPU(_PRCPU *cpu);
PR_EXTERN(void) _PR_MD_INIT_RUNNING_CPU(_PRCPU *cpu);
PR_EXTERN(PRInt32) _PR_MD_PAUSE_CPU(PRIntervalTime timeout);

View File

@ -0,0 +1,240 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
#include <signal.h>
#include <unistd.h>
#include <memory.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <errno.h>
/*
* Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
* PRInt32* pointer to a _PRSockLen_t* pointer.
*/
#define _PRSockLen_t int
/*
** Global lock variable used to bracket calls into rusty libraries that
** aren't thread safe (like libc, libX, etc).
*/
static PRLock *_pr_rename_lock = NULL;
static PRMonitor *_pr_Xfe_mon = NULL;
/*
* Variables used by the GC code, initialized in _MD_InitSegs().
* _pr_zero_fd should be a static variable. Unfortunately, there is
* still some Unix-specific code left in function PR_GrowSegment()
* in file memory/prseg.c that references it, so it needs
* to be a global variable for now.
*/
PRInt32 _pr_zero_fd = -1;
static PRLock *_pr_md_lock = NULL;
sigset_t timer_set;
void _PR_UnixInit()
{
struct sigaction sigact;
int rv;
sigemptyset(&timer_set);
sigact.sa_handler = SIG_IGN;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
rv = sigaction(SIGPIPE, &sigact, 0);
PR_ASSERT(0 == rv);
_pr_rename_lock = PR_NewLock();
PR_ASSERT(NULL != _pr_rename_lock);
_pr_Xfe_mon = PR_NewMonitor();
PR_ASSERT(NULL != _pr_Xfe_mon);
}
/*
*-----------------------------------------------------------------------
*
* PR_Now --
*
* Returns the current time in microseconds since the epoch.
* The epoch is midnight January 1, 1970 GMT.
* The implementation is machine dependent. This is the Unix
* implementation.
* Cf. time_t time(time_t *tp)
*
*-----------------------------------------------------------------------
*/
PR_IMPLEMENT(PRTime)
PR_Now(void)
{
struct timeval tv;
PRInt64 s, us, s2us;
GETTIMEOFDAY(&tv);
LL_I2L(s2us, PR_USEC_PER_SEC);
LL_I2L(s, tv.tv_sec);
LL_I2L(us, tv.tv_usec);
LL_MUL(s, s, s2us);
LL_ADD(s, s, us);
return s;
}
PRIntervalTime
_PR_UNIX_GetInterval()
{
struct timeval time;
PRIntervalTime ticks;
(void)GETTIMEOFDAY(&time); /* fallicy of course */
ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds */
ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */
return ticks;
} /* _PR_SUNOS_GetInterval */
PRIntervalTime _PR_UNIX_TicksPerSecond()
{
return 1000; /* this needs some work :) */
}
/************************************************************************/
/*
** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread
** safe. Unfortunately, neither is mozilla. To make these programs work
** in a pre-emptive threaded environment, we need to use a lock.
*/
void PR_XLock()
{
PR_EnterMonitor(_pr_Xfe_mon);
}
void PR_XUnlock()
{
PR_ExitMonitor(_pr_Xfe_mon);
}
PRBool PR_XIsLocked()
{
return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE;
}
void PR_XWait(int ms)
{
PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms));
}
void PR_XNotify(void)
{
PR_Notify(_pr_Xfe_mon);
}
void PR_XNotifyAll(void)
{
PR_NotifyAll(_pr_Xfe_mon);
}
#if !defined(BEOS)
#ifdef HAVE_BSD_FLOCK
#include <sys/file.h>
PR_IMPLEMENT(PRStatus)
_MD_LOCKFILE (PRInt32 f)
{
PRInt32 rv;
rv = flock(f, LOCK_EX);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
PR_IMPLEMENT(PRStatus)
_MD_TLOCKFILE (PRInt32 f)
{
PRInt32 rv;
rv = flock(f, LOCK_EX|LOCK_NB);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
PR_IMPLEMENT(PRStatus)
_MD_UNLOCKFILE (PRInt32 f)
{
PRInt32 rv;
rv = flock(f, LOCK_UN);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
#else
PR_IMPLEMENT(PRStatus)
_MD_LOCKFILE (PRInt32 f)
{
PRInt32 rv;
rv = lockf(f, F_LOCK, 0);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
PR_IMPLEMENT(PRStatus)
_MD_TLOCKFILE (PRInt32 f)
{
PRInt32 rv;
rv = lockf(f, F_TLOCK, 0);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
PR_IMPLEMENT(PRStatus)
_MD_UNLOCKFILE (PRInt32 f)
{
PRInt32 rv;
rv = lockf(f, F_ULOCK, 0);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
#endif
PR_IMPLEMENT(PRStatus)
_MD_GETHOSTNAME (char *name, PRUint32 namelen)
{
PRIntn rv;
rv = gethostname(name, namelen);
if (0 == rv) {
return PR_SUCCESS;
}
_PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,783 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
/*
** Global lock variable used to bracket calls into rusty libraries that
** aren't thread safe (like libc, libX, etc).
*/
static PRLock *_pr_rename_lock = NULL;
void
_MD_InitIO (void)
{
}
PRStatus
_MD_open_dir (_MDDir *md,const char *name)
{
int err;
md->d = opendir(name);
if (!md->d) {
err = _MD_ERRNO();
_PR_MD_MAP_OPENDIR_ERROR(err);
return PR_FAILURE;
}
return PR_SUCCESS;
}
char*
_MD_read_dir (_MDDir *md, PRIntn flags)
{
struct dirent *de;
int err;
for (;;) {
/*
* XXX: readdir() is not MT-safe
*/
de = readdir(md->d);
if (!de) {
err = _MD_ERRNO();
_PR_MD_MAP_READDIR_ERROR(err);
return 0;
}
if ((flags & PR_SKIP_DOT) &&
(de->d_name[0] == '.') && (de->d_name[1] == 0))
continue;
if ((flags & PR_SKIP_DOT_DOT) &&
(de->d_name[0] == '.') && (de->d_name[1] == '.') &&
(de->d_name[2] == 0))
continue;
if ((flags & PR_SKIP_HIDDEN) && (de->d_name[1] == '.'))
continue;
break;
}
return de->d_name;
}
PRInt32
_MD_close_dir (_MDDir *md)
{
int rv = 0, err;
if (md->d) {
rv = closedir(md->d);
if (rv == -1) {
err = _MD_ERRNO();
_PR_MD_MAP_CLOSEDIR_ERROR(err);
}
}
return(rv);
}
void
_MD_make_nonblock (PRFileDesc *fd)
{
int blocking = 1;
setsockopt(fd->secret->md.osfd, SOL_SOCKET, SO_NONBLOCK, &blocking, sizeof(blocking));
}
PRInt32
_MD_open (const char *name, PRIntn flags, PRIntn mode)
{
PRInt32 osflags;
PRInt32 rv, err;
if (flags & PR_RDWR) {
osflags = O_RDWR;
} else if (flags & PR_WRONLY) {
osflags = O_WRONLY;
} else {
osflags = O_RDONLY;
}
if (flags & PR_APPEND)
osflags |= O_APPEND;
if (flags & PR_TRUNCATE)
osflags |= O_TRUNC;
if (flags & PR_SYNC) {
/* Ummmm. BeOS doesn't appear to
support sync in any way shape or
form. */
return PR_NOT_IMPLEMENTED_ERROR;
}
/*
** On creations we hold the 'create' lock in order to enforce
** the semantics of PR_Rename. (see the latter for more details)
*/
if (flags & PR_CREATE_FILE)
{
osflags |= O_CREAT ;
if (NULL !=_pr_rename_lock)
PR_Lock(_pr_rename_lock);
}
rv = open(name, osflags, mode);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_OPEN_ERROR(err);
}
if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
PR_Unlock(_pr_rename_lock);
return rv;
}
PRInt32
_MD_close_file (PRInt32 osfd)
{
PRInt32 rv, err;
rv = close(osfd);
if (rv == -1) {
err = _MD_ERRNO();
_PR_MD_MAP_CLOSE_ERROR(err);
}
return(rv);
}
PRInt32
_MD_read (PRFileDesc *fd, void *buf, PRInt32 amount)
{
PRInt32 rv, err;
PRInt32 osfd = fd->secret->md.osfd;
rv = read( osfd, buf, amount );
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_READ_ERROR(err);
}
return(rv);
}
PRInt32
_MD_write (PRFileDesc *fd, const void *buf, PRInt32 amount)
{
PRInt32 rv, err;
PRInt32 osfd = fd->secret->md.osfd;
rv = write( osfd, buf, amount );
if( rv < 0 ) {
err = _MD_ERRNO();
_PR_MD_MAP_WRITE_ERROR(err);
}
return( rv );
}
PRInt32
_MD_writev (PRFileDesc *fd, struct PRIOVec *iov, PRInt32 iov_size,
PRIntervalTime timeout)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRInt32
_MD_lseek (PRFileDesc *fd, PRInt32 offset, int whence)
{
PRInt32 rv, err;
rv = lseek (fd->secret->md.osfd, offset, whence);
if (rv == -1) {
err = _MD_ERRNO();
_PR_MD_MAP_LSEEK_ERROR(err);
}
return( rv );
}
PRInt64
_MD_lseek64 (PRFileDesc *fd, PRInt64 offset, int whence)
{
PRInt32 rv, err;
/* According to the BeOS headers, lseek accepts a
* variable of type off_t for the offset, and off_t
* is defined to be a 64-bit value. So no special
* cracking needs to be done on "offset".
*/
rv = lseek (fd->secret->md.osfd, offset, whence);
if (rv == -1) {
err = _MD_ERRNO();
_PR_MD_MAP_LSEEK_ERROR(err);
}
return( rv );
}
PRInt32
_MD_fsync (PRFileDesc *fd)
{
PRInt32 rv, err;
rv = fsync(fd->secret->md.osfd);
if (rv == -1) {
err = _MD_ERRNO();
_PR_MD_MAP_FSYNC_ERROR(err);
}
return(rv);
}
PRInt32
_MD_delete (const char *name)
{
PRInt32 rv, err;
rv = unlink(name);
if (rv == -1)
{
err = _MD_ERRNO();
_PR_MD_MAP_UNLINK_ERROR(err);
}
return (rv);
}
PRInt32
_MD_getfileinfo (const char *fn, PRFileInfo *info)
{
struct stat sb;
PRInt32 rv, err;
PRInt64 s, s2us;
rv = stat(fn, &sb);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_STAT_ERROR(err);
} else if (info) {
if (S_IFREG & sb.st_mode)
info->type = PR_FILE_FILE;
else if (S_IFDIR & sb.st_mode)
info->type = PR_FILE_DIRECTORY;
else
info->type = PR_FILE_OTHER;
/* Must truncate file size for the 32 bit
version */
info->size = (sb.st_size & 0xffffffff);
LL_I2L(s, sb.st_mtime);
LL_I2L(s2us, PR_USEC_PER_SEC);
LL_MUL(s, s, s2us);
info->modifyTime = s;
LL_I2L(s, sb.st_ctime);
LL_MUL(s, s, s2us);
info->creationTime = s;
}
return rv;
}
PRInt32
_MD_getfileinfo64 (const char *fn, PRFileInfo64 *info)
{
struct stat sb;
PRInt32 rv, err;
PRInt64 s, s2us;
rv = stat(fn, &sb);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_STAT_ERROR(err);
} else if (info) {
if (S_IFREG & sb.st_mode)
info->type = PR_FILE_FILE;
else if (S_IFDIR & sb.st_mode)
info->type = PR_FILE_DIRECTORY;
else
info->type = PR_FILE_OTHER;
/* For the 64 bit version we can use
* the native st_size without modification
*/
info->size = sb.st_size;
LL_I2L(s, sb.st_mtime);
LL_I2L(s2us, PR_USEC_PER_SEC);
LL_MUL(s, s, s2us);
info->modifyTime = s;
LL_I2L(s, sb.st_ctime);
LL_MUL(s, s, s2us);
info->creationTime = s;
}
return rv;
}
PRInt32
_MD_getopenfileinfo (const PRFileDesc *fd, PRFileInfo *info)
{
struct stat sb;
PRInt64 s, s2us;
PRInt32 rv, err;
rv = fstat(fd->secret->md.osfd, &sb);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_FSTAT_ERROR(err);
} else if (info) {
if (info) {
if (S_IFREG & sb.st_mode)
info->type = PR_FILE_FILE ;
else if (S_IFDIR & sb.st_mode)
info->type = PR_FILE_DIRECTORY;
else
info->type = PR_FILE_OTHER;
/* Use lower 32 bits of file size */
info->size = ( sb.st_size & 0xffffffff);
LL_I2L(s, sb.st_mtime);
LL_I2L(s2us, PR_USEC_PER_SEC);
LL_MUL(s, s, s2us);
info->modifyTime = s;
LL_I2L(s, sb.st_ctime);
LL_MUL(s, s, s2us);
info->creationTime = s;
}
}
return rv;
}
PRInt32
_MD_getopenfileinfo64 (const PRFileDesc *fd, PRFileInfo64 *info)
{
struct stat sb;
PRInt64 s, s2us;
PRInt32 rv, err;
rv = fstat(fd->secret->md.osfd, &sb);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_FSTAT_ERROR(err);
} else if (info) {
if (info) {
if (S_IFREG & sb.st_mode)
info->type = PR_FILE_FILE ;
else if (S_IFDIR & sb.st_mode)
info->type = PR_FILE_DIRECTORY;
else
info->type = PR_FILE_OTHER;
info->size = sb.st_size;
LL_I2L(s, sb.st_mtime);
LL_I2L(s2us, PR_USEC_PER_SEC);
LL_MUL(s, s, s2us);
info->modifyTime = s;
LL_I2L(s, sb.st_ctime);
LL_MUL(s, s, s2us);
info->creationTime = s;
}
}
return rv;
}
PRInt32
_MD_rename (const char *from, const char *to)
{
PRInt32 rv = -1, err;
/*
** This is trying to enforce the semantics of WINDOZE' rename
** operation. That means one is not allowed to rename over top
** of an existing file. Holding a lock across these two function
** and the open function is known to be a bad idea, but ....
*/
if (NULL != _pr_rename_lock)
PR_Lock(_pr_rename_lock);
if (0 == access(to, F_OK))
PR_SetError(PR_FILE_EXISTS_ERROR, 0);
else
{
rv = rename(from, to);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_RENAME_ERROR(err);
}
}
if (NULL != _pr_rename_lock)
PR_Unlock(_pr_rename_lock);
return rv;
}
PRInt32
_MD_access (const char *name, PRIntn how)
{
PRInt32 rv, err;
int amode;
switch (how) {
case PR_ACCESS_WRITE_OK:
amode = W_OK;
break;
case PR_ACCESS_READ_OK:
amode = R_OK;
break;
case PR_ACCESS_EXISTS:
amode = F_OK;
break;
default:
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
rv = -1;
goto done;
}
rv = access(name, amode);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_ACCESS_ERROR(err);
}
done:
return(rv);
}
PRInt32
_MD_stat (const char *name, struct stat *buf)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRInt32
_MD_mkdir (const char *name, PRIntn mode)
{
status_t rv;
int err;
/*
** This lock is used to enforce rename semantics as described
** in PR_Rename. Look there for more fun details.
*/
if (NULL !=_pr_rename_lock)
PR_Lock(_pr_rename_lock);
rv = mkdir(name, mode);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_MKDIR_ERROR(err);
}
if (NULL !=_pr_rename_lock)
PR_Unlock(_pr_rename_lock);
return rv;
}
PRInt32
_MD_rmdir (const char *name)
{
int rv, err;
rv = rmdir(name);
if (rv == -1) {
err = _MD_ERRNO();
_PR_MD_MAP_RMDIR_ERROR(err);
}
return rv;
}
PRInt32
_MD_pr_poll (PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
{
PRPollDesc *pd, *epd;
PRInt32 n, err, pdcnt;
PRThread *me = _PR_MD_CURRENT_THREAD();
fd_set rd, wt, ex;
struct timeval tv, *tvp = NULL;
int maxfd = -1;
int rv;
ConnectListNode currentConnectList[64];
int currentConnectListCount = 0;
int i,j;
int connectResult = 0;
int connectError = 0;
/*
* For restarting _MD_SELECT() if it is interrupted by a signal.
* We use these variables to figure out how much time has elapsed
* and how much of the timeout still remains.
*/
PRIntervalTime start, elapsed, remaining;
FD_ZERO(&rd);
FD_ZERO(&wt);
FD_ZERO(&ex);
for (pd = pds, epd = pd + npds; pd < epd; pd++) {
PRInt32 osfd;
PRInt16 in_flags = pd->in_flags;
PRFileDesc *bottom = pd->fd;
if ((NULL == bottom) || (in_flags == 0)) {
continue;
}
while (bottom->lower != NULL) {
bottom = bottom->lower;
}
osfd = bottom->secret->md.osfd;
if( (in_flags & PR_POLL_WRITE) || (in_flags & PR_POLL_EXCEPT) ) {
PR_Lock( _connectLock );
for( i = 0; i < connectCount; i++ ) {
if( connectList[i].osfd == osfd ) {
memcpy( &currentConnectList[currentConnectListCount], &connectList[i], sizeof( connectList[i] ) );
currentConnectListCount++;
break;
}
}
PR_Unlock( _connectLock );
}
if (in_flags & PR_POLL_READ) {
FD_SET(osfd, &rd);
if( osfd > maxfd ) maxfd = osfd;
}
}
if (timeout != PR_INTERVAL_NO_TIMEOUT) {
tv.tv_sec = PR_IntervalToSeconds(timeout);
tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC;
tvp = &tv;
start = PR_IntervalNow();
}
if( currentConnectListCount > 0 ) {
tv.tv_sec = 0;
tv.tv_usec = 100000L;
tvp = &tv;
start = PR_IntervalNow();
}
retry:
if( currentConnectListCount > 0 ) {
for( i = 0; i < currentConnectListCount; i++ ) {
connectResult = connect( currentConnectList[i].osfd,
&currentConnectList[i].addr,
&currentConnectList[i].addrlen );
connectError = _MD_ERRNO();
if( ( connectResult < 0 ) &&
( connectError == EINTR ||
connectError == EWOULDBLOCK ||
connectError == EINPROGRESS ||
connectError == EALREADY ) ) {
continue;
}
PR_Lock( _connectLock );
for( j = 0; j < connectCount; j++ ) {
if( connectList[j].osfd == currentConnectList[i].osfd ) {
if( j == ( connectCount - 1 ) ) {
connectList[j].osfd = -1;
} else {
for( ; j < connectCount; j++ )
memcpy( &connectList[j], &connectList[j+1], sizeof( connectList[j] ) );
}
connectCount--;
break;
}
}
PR_Unlock( _connectLock );
FD_ZERO( &rd );
FD_SET( currentConnectList[i].osfd, &wt );
FD_SET( currentConnectList[i].osfd, &ex );
n = 1;
goto afterselect;
}
}
if( maxfd == -1 ) {
snooze( 100000L );
goto retry;
}
n = select(maxfd + 1, &rd, NULL, NULL, tvp);
afterselect:
if ( (n == -1 && errno == EINTR) || (n == 0 && currentConnectListCount > 0 ) ) {
if (timeout == PR_INTERVAL_NO_TIMEOUT) {
goto retry;
} else {
elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
if (elapsed > timeout) {
n = 0; /* timed out */
} else {
remaining = timeout - elapsed;
tv.tv_sec = PR_IntervalToSeconds(remaining);
tv.tv_usec = PR_IntervalToMicroseconds(
remaining - PR_SecondsToInterval(tv.tv_sec));
goto retry;
}
}
}
if (n > 0) {
n = 0;
for (pd = pds, epd = pd + npds; pd < epd; pd++) {
PRInt32 osfd;
PRInt16 in_flags = pd->in_flags;
PRInt16 out_flags = 0;
PRFileDesc *bottom = pd->fd;
if ((NULL == bottom) || (in_flags == 0)) {
pd->out_flags = 0;
continue;
}
while (bottom->lower != NULL) {
bottom = bottom->lower;
}
osfd = bottom->secret->md.osfd;
if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, &rd)) {
out_flags |= PR_POLL_READ;
}
if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, &wt)) {
out_flags |= PR_POLL_WRITE;
}
if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, &ex)) {
out_flags |= PR_POLL_EXCEPT;
}
if ( FD_ISSET(osfd, &wt) && FD_ISSET(osfd, &ex ) ) {
bottom->secret->md.connectReturnValue = connectResult;
bottom->secret->md.connectReturnError = connectError;
bottom->secret->md.connectValueValid = PR_TRUE;
}
pd->out_flags = out_flags;
if (out_flags) {
n++;
}
}
PR_ASSERT(n > 0);
} else if (n < 0) {
err = _MD_ERRNO();
if (err == EBADF) {
/* Find the bad fds */
n = 0;
for (pd = pds, epd = pd + npds; pd < epd; pd++) {
int optval;
int optlen = sizeof(optval);
PRFileDesc *bottom = pd->fd;
pd->out_flags = 0;
if ((NULL == bottom) || (pd->in_flags == 0)) {
continue;
}
while (bottom->lower != NULL) {
bottom = bottom->lower;
}
#if 0
/*
* BeOS doesn't have this feature of getsockopt.
*/
if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
SO_TYPE, (char *) &optval, &optlen) == -1) {
PR_ASSERT(_MD_ERRNO() == ENOTSOCK);
if (_MD_ERRNO() == ENOTSOCK) {
pd->out_flags = PR_POLL_NVAL;
n++;
}
}
#endif
}
PR_ASSERT(n > 0);
} else {
PR_ASSERT(err != EINTR); /* should have been handled above */
_PR_MD_MAP_SELECT_ERROR(err);
}
}
return n;
}
/*
* File locking.
*/
PRStatus
_MD_lockfile (PRInt32 osfd)
{
PRInt32 rv;
struct flock linfo;
linfo.l_type =
linfo.l_whence = SEEK_SET;
linfo.l_start = 0;
linfo.l_len = 0;
rv = fcntl(osfd, F_SETLKW, &linfo);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
PRStatus
_MD_tlockfile (PRInt32 osfd)
{
PRInt32 rv;
struct flock linfo;
linfo.l_type =
linfo.l_whence = SEEK_SET;
linfo.l_start = 0;
linfo.l_len = 0;
rv = fcntl(osfd, F_SETLK, &linfo);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
return PR_FAILURE;
}
PRStatus
_MD_unlockfile (PRInt32 osfd)
{
PRInt32 rv;
struct flock linfo;
linfo.l_type =
linfo.l_whence = SEEK_SET;
linfo.l_start = 0;
linfo.l_len = 0;
rv = fcntl(osfd, F_UNLCK, &linfo);
if (rv == 0)
return PR_SUCCESS;
_PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO());
return PR_FAILURE;
}

View File

@ -0,0 +1,18 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
PR_EXTERN(void) _PR_MD_INIT_SEGS(void);
PR_EXTERN(PRStatus) _PR_MD_ALLOC_SEGMENT(PRSegment *seg, PRUint32 size, void *vaddr);
PR_EXTERN(void) _PR_MD_FREE_SEGMENT(PRSegment *seg);

View File

@ -0,0 +1,92 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
#include <stdlib.h>
PRLock *_connectLock = NULL;
PRUint32 connectCount = 0;
ConnectListNode connectList[64];
void
_MD_cleanup_before_exit (void)
{
}
void
_MD_exit (PRIntn status)
{
exit(status);
}
void
_MD_early_init (void)
{
}
static PRLock *monitor = NULL;
void
_MD_final_init (void)
{
_connectLock = PR_NewLock();
PR_ASSERT(NULL != _connectLock);
connectCount = 0;
}
void
_MD_AtomicInit (void)
{
if (monitor == NULL) {
monitor = PR_NewLock();
}
}
/*
** This is exceedingly messy. atomic_add returns the last value, NSPR expects the new value.
** We just add or subtract 1 from the result. The actual memory update is atomic.
*/
PRInt32
_MD_AtomicAdd( PRInt32 *ptr, PRInt32 val )
{
return( ( atomic_add( (long *)ptr, val ) ) + val );
}
PRInt32
_MD_AtomicIncrement( PRInt32 *val )
{
return( ( atomic_add( (long *)val, 1 ) ) + 1 );
}
PRInt32
_MD_AtomicDecrement( PRInt32 *val )
{
return( ( atomic_add( (long *)val, -1 ) ) - 1 );
}
PRInt32
_MD_AtomicSet( PRInt32 *val, PRInt32 newval )
{
PRInt32 rv;
if (!_pr_initialized) {
_PR_ImplicitInitialization();
}
PR_Lock(monitor);
rv = *val;
*val = newval;
PR_Unlock(monitor);
return rv;
}

View File

@ -0,0 +1,39 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
PR_EXTERN(PRStatus)
_PR_MD_CREATE_FILE_MAP(PRFileMap *fmap, PRInt64 size)
{
return PR_FAILURE;
}
PR_EXTERN(void *)
_PR_MD_MEM_MAP(PRFileMap *fmap, PRInt64 offset, PRUint32 len)
{
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
return 0;
}
PR_EXTERN(PRStatus)
_PR_MD_MEM_UNMAP(void *addr, PRUint32 size)
{
return PR_FAILURE;
}
PR_EXTERN(PRStatus)
_PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap)
{
return PR_FAILURE;
}

View File

@ -0,0 +1,648 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
#include <signal.h>
#include <unistd.h>
#include <memory.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
/*
* Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
* PRInt32* pointer to a _PRSockLen_t* pointer.
*/
#define _PRSockLen_t int
/*
** Global lock variable used to bracket calls into rusty libraries that
** aren't thread safe (like libc, libX, etc).
*/
static PRLock *_pr_rename_lock = NULL;
static PRMonitor *_pr_Xfe_mon = NULL;
/*
** This is a support routine to handle "deferred" i/o on sockets.
** It uses "select", so it is subject to all of the BeOS limitations
** (only READ notification, only sockets)
*/
#define READ_FD 1
#define WRITE_FD 2
static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
PRIntervalTime timeout)
{
PRInt32 rv = -1;
struct timeval tv, *tvp;
PRThread *me = _PR_MD_CURRENT_THREAD();
PRIntervalTime epoch, now, elapsed, remaining;
PRInt32 syserror;
fd_set rd_wr;
switch (timeout) {
case PR_INTERVAL_NO_WAIT:
PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
break;
case PR_INTERVAL_NO_TIMEOUT:
/*
* This is a special case of the 'default' case below.
* Please see the comments there.
*/
tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
tv.tv_usec = 0;
tvp = &tv;
FD_ZERO(&rd_wr);
do {
FD_SET(osfd, &rd_wr);
if (fd_type == READ_FD)
rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, tvp);
else
rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, tvp);
if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
if (syserror == EBADF) {
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
} else {
PR_SetError(PR_UNKNOWN_ERROR, syserror);
}
if( _PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
rv = -1;
break;
}
break;
}
} while (rv == 0 || (rv == -1 && syserror == EINTR));
break;
default:
now = epoch = PR_IntervalNow();
remaining = timeout;
tvp = &tv;
FD_ZERO(&rd_wr);
do {
/*
* We block in _MD_SELECT for at most
* _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
* so that there is an upper limit on the delay
* before the interrupt bit is checked.
*/
tv.tv_sec = PR_IntervalToSeconds(remaining);
if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
tv.tv_usec = 0;
} else {
tv.tv_usec = PR_IntervalToMicroseconds(
remaining -
PR_SecondsToInterval(tv.tv_sec));
}
FD_SET(osfd, &rd_wr);
if (fd_type == READ_FD)
rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, tvp);
else
rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, tvp);
/*
* we don't consider EINTR a real error
*/
if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
if (syserror == EBADF) {
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
} else {
PR_SetError(PR_UNKNOWN_ERROR, syserror);
}
break;
}
if (_PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
rv = -1;
break;
}
/*
* We loop again if _MD_SELECT timed out or got interrupted
* by a signal, and the timeout deadline has not passed yet.
*/
if (rv == 0 || (rv == -1 && syserror == EINTR)) {
/*
* If _MD_SELECT timed out, we know how much time
* we spent in blocking, so we can avoid a
* PR_IntervalNow() call.
*/
if (rv == 0) {
now += PR_SecondsToInterval(tv.tv_sec)
+ PR_MicrosecondsToInterval(tv.tv_usec);
} else {
now = PR_IntervalNow();
}
elapsed = (PRIntervalTime) (now - epoch);
if (elapsed >= timeout) {
PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
rv = -1;
break;
} else {
remaining = timeout - elapsed;
}
}
} while (rv == 0 || (rv == -1 && syserror == EINTR));
break;
}
return(rv);
}
PRInt32
_MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags,
PRIntervalTime timeout)
{
PRInt32 osfd = fd->secret->md.osfd;
PRInt32 rv, err;
PRThread *me = _PR_MD_CURRENT_THREAD();
if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) {
_PR_MD_MAP_RECV_ERROR(EPIPE);
return -1;
}
while ((rv = recv(osfd, buf, amount, flags)) == -1) {
err = _MD_ERRNO();
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
if (fd->secret->nonblocking) {
break;
}
/* If socket was supposed to be blocking,
wait a while for the condition to be
satisfied. */
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
goto done;
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
continue;
} else {
break;
}
}
if (rv < 0) {
_PR_MD_MAP_RECV_ERROR(err);
}
done:
return(rv);
}
PRInt32
_MD_recvfrom (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
{
PRInt32 osfd = fd->secret->md.osfd;
PRInt32 rv, err;
PRThread *me = _PR_MD_CURRENT_THREAD();
while ((*addrlen = PR_NETADDR_SIZE(addr)),
((rv = recvfrom(osfd, buf, amount, flags,
(struct sockaddr *) addr,
(_PRSockLen_t *)addrlen)) == -1)) {
err = _MD_ERRNO();
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
if (fd->secret->nonblocking) {
break;
}
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
goto done;
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
continue;
} else {
break;
}
}
if (rv < 0) {
_PR_MD_MAP_RECVFROM_ERROR(err);
}
done:
return(rv);
}
PRInt32
_MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags,
PRIntervalTime timeout)
{
PRInt32 osfd = fd->secret->md.osfd;
PRInt32 rv, err;
PRThread *me = _PR_MD_CURRENT_THREAD();
if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE)
{
_PR_MD_MAP_SEND_ERROR(EPIPE);
return -1;
}
while ((rv = send(osfd, buf, amount, flags)) == -1) {
err = _MD_ERRNO();
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
if (fd->secret->nonblocking) {
break;
}
if( _PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
return -1;
}
/* in UNIX implementations, you could do a socket_io_wait here.
* but since BeOS doesn't yet support WRITE notification in select,
* you're spanked.
*/
snooze( 10000L );
continue;
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
continue;
} else {
break;
}
}
if (rv < 0) {
_PR_MD_MAP_SEND_ERROR(err);
}
return(rv);
}
PRInt32
_MD_sendto (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
{
PRInt32 osfd = fd->secret->md.osfd;
PRInt32 rv, err;
PRThread *me = _PR_MD_CURRENT_THREAD();
while ((rv = sendto(osfd, buf, amount, flags,
(struct sockaddr *) addr, addrlen)) == -1) {
err = _MD_ERRNO();
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
if (fd->secret->nonblocking) {
break;
}
printf( "This should be a blocking sendto call!!!\n" );
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
continue;
} else {
break;
}
}
if (rv < 0) {
_PR_MD_MAP_SENDTO_ERROR(err);
}
return(rv);
}
PRInt32
_MD_accept (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen,
PRIntervalTime timeout)
{
PRInt32 osfd = fd->secret->md.osfd;
PRInt32 rv, err;
PRThread *me = _PR_MD_CURRENT_THREAD();
while ((rv = accept(osfd, (struct sockaddr *) addr,
(_PRSockLen_t *)addrlen)) == -1) {
err = _MD_ERRNO();
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
if (fd->secret->nonblocking) {
break;
}
/* If it's SUPPOSED to be a blocking thread, wait
* a while to see if the triggering condition gets
* satisfied.
*/
/* Assume that we're always using a native thread */
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
goto done;
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
continue;
} else {
break;
}
}
if (addr) addr->raw.family = AF_INET;
if (rv < 0) {
_PR_MD_MAP_ACCEPT_ERROR(err);
}
done:
#ifdef _PR_HAVE_SOCKADDR_LEN
if (rv != -1) {
/* Mask off the first byte of struct sockaddr (the length field) */
if (addr) {
*((unsigned char *) addr) = 0;
#ifdef IS_LITTLE_ENDIAN
addr->raw.family = ntohs(addr->raw.family);
#endif
}
}
#endif /* _PR_HAVE_SOCKADDR_LEN */
return(rv);
}
PRInt32
_MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
PRIntervalTime timeout)
{
PRInt32 osfd = fd->secret->md.osfd;
PRInt32 rv, err;
PRThread *me = _PR_MD_CURRENT_THREAD();
fd->secret->md.connectValueValid = PR_FALSE;
retry:
if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
err = _MD_ERRNO();
fd->secret->md.connectReturnValue = rv;
fd->secret->md.connectReturnError = err;
fd->secret->md.connectValueValid = PR_TRUE;
if( err == EINTR ) {
if( _PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
return -1;
}
snooze( 100000L );
goto retry;
}
if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) {
/*
** There's no timeout on this connect, but that's not
** a big deal, since the connect times out anyways
** after 30 seconds. Just sleep for 1/10th of a second
** and retry until we go through or die.
*/
if( _PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
return -1;
}
goto retry;
}
if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) {
PR_Lock(_connectLock);
connectList[connectCount].osfd = osfd;
memcpy(&connectList[connectCount].addr, addr, addrlen);
connectList[connectCount].addrlen = addrlen;
connectList[connectCount].timeout = timeout;
connectCount++;
PR_Unlock(_connectLock);
_PR_MD_MAP_CONNECT_ERROR(err);
return rv;
}
_PR_MD_MAP_CONNECT_ERROR(err);
}
return rv;
}
PRInt32
_MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
{
PRInt32 rv, err;
rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_BIND_ERROR(err);
}
return(rv);
}
PRInt32
_MD_listen (PRFileDesc *fd, PRIntn backlog)
{
PRInt32 rv, err;
/* Bug workaround! Setting listen to 0 on Be accepts no connections.
** On most UN*Xes this sets the default.
*/
if( backlog == 0 ) backlog = 5;
rv = listen(fd->secret->md.osfd, backlog);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_LISTEN_ERROR(err);
}
return(rv);
}
PRInt32
_MD_shutdown (PRFileDesc *fd, PRIntn how)
{
PRInt32 rv, err;
if (how == PR_SHUTDOWN_SEND)
fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE;
else if (how == PR_SHUTDOWN_RCV)
fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ;
else if (how == PR_SHUTDOWN_BOTH) {
fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ);
}
return 0;
}
PRInt32
_MD_socketpair (int af, int type, int flags, PRInt32 *osfd)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRInt32
_MD_close_socket (PRInt32 osfd)
{
closesocket( osfd );
}
PRStatus
_MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
{
PRInt32 rv, err;
rv = getsockname(fd->secret->md.osfd,
(struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_GETSOCKNAME_ERROR(err);
}
return rv==0?PR_SUCCESS:PR_FAILURE;
}
PRStatus
_MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
{
PRInt32 rv, err;
rv = getpeername(fd->secret->md.osfd,
(struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_GETPEERNAME_ERROR(err);
}
return rv==0?PR_SUCCESS:PR_FAILURE;
}
PRStatus
_MD_getsockopt (PRFileDesc *fd, PRInt32 level,
PRInt32 optname, char* optval, PRInt32* optlen)
{
return PR_NOT_IMPLEMENTED_ERROR;
#if 0
PRInt32 rv, err;
rv = getsockopt(fd->secret->md.osfd, level, optname,
optval, (_PRSockLen_t *)optlen);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_GETSOCKOPT_ERROR(err);
}
return rv==0?PR_SUCCESS:PR_FAILURE;
#endif
}
PRStatus
_MD_setsockopt (PRFileDesc *fd, PRInt32 level,
PRInt32 optname, const char* optval, PRInt32 optlen)
{
PRInt32 rv, err;
rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
if (rv < 0) {
err = _MD_ERRNO();
_PR_MD_MAP_SETSOCKOPT_ERROR(err);
}
return rv==0?PR_SUCCESS:PR_FAILURE;
}
PRInt32
_MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
void *buf, PRInt32 amount, PRIntervalTime timeout)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRInt32
_MD_transmitfile (PRFileDesc *sock, PRFileDesc *file, const void *headers, PRInt32 hlen, PRInt32 flags, PRIntervalTime timeout)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRInt32
_MD_socket (int af, int type, int flags)
{
PRInt32 osfd, err;
osfd = socket( af, type, 0 );
if( -1 == osfd ) {
err = _MD_ERRNO();
_PR_MD_MAP_SOCKET_ERROR( err );
}
return( osfd );
}
PRInt32
_MD_socketavailable (PRFileDesc *fd)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRInt32
_MD_get_socket_error (void)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRStatus
_MD_gethostname (char *name, PRUint32 namelen)
{
PRInt32 rv, err;
rv = gethostname(name, namelen);
if (rv == 0)
{
err = _MD_ERRNO();
_PR_MD_MAP_GETHOSTNAME_ERROR(err);
return PR_FAILURE;
}
return PR_SUCCESS;
}
PRInt32
_MD_beos_get_nonblocking_connect_error(PRFileDesc *fd)
{
int rv;
int flags = 0;
if( fd->secret->md.connectValueValid == PR_TRUE )
if( fd->secret->md.connectReturnValue == -1 )
return fd->secret->md.connectReturnError;
else
return 0; /* No error */
rv = recv(fd->secret->md.osfd, NULL, 0, flags);
PR_ASSERT(-1 == rv || 0 == rv);
if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) {
return errno;
}
return 0; /* no error */
}

View File

@ -0,0 +1,39 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
PRProcess*
_MD_create_process (const char *path, char *const *argv,
char *const *envp, const PRProcessAttr *attr)
{
return NULL;
}
PRStatus
_MD_detach_process (PRProcess *process)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRStatus
_MD_wait_process (PRProcess *process, PRInt32 *exitCode)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PRStatus
_MD_kill_process (PRProcess *process)
{
return PR_NOT_IMPLEMENTED_ERROR;
}

View File

@ -0,0 +1,35 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
void
_PR_InitSegs (void)
{
}
PR_IMPLEMENT(void)
_MD_init_segs (void)
{
}
PR_IMPLEMENT(PRStatus)
_MD_alloc_segment (PRSegment *seg, PRUint32 size, void *vaddr)
{
return PR_NOT_IMPLEMENTED_ERROR;
}
PR_IMPLEMENT(void)
_MD_free_segment (PRSegment *seg)
{
}

View File

@ -0,0 +1,27 @@
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "MPL"); you may not use this file except in
# compliance with the MPL. You may obtain a copy of the MPL at
# http://www.mozilla.org/MPL/
#
# Software distributed under the MPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
# for the specific language governing rights and limitations under the
# MPL.
#
# this file lists the source files to be compiled (used in Makefile) and
# then enumerated as object files (in objs.mk) for inclusion in the NSPR
# shared library
MDCSRCS = \
beos.c \
beos_errors.c \
bfile.c \
bmisc.c \
bnet.c \
bproc.c \
bseg.c \
btime.c \
bmmap.c \
$(NULL)

View File

@ -0,0 +1,51 @@
/* -*- Mode: C++; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http:// www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*/
#include "primpl.h"
#include <kernel/OS.h>
static bigtime_t start;
PRTime
_MD_now (void)
{
return (PRTime)real_time_clock_usecs();
}
void
_MD_interval_init (void)
{
/* grab the base interval time */
start = real_time_clock_usecs();
}
PRIntervalTime
_MD_get_interval (void)
{
return( (PRIntervalTime) real_time_clock_usecs() / 10 );
#if 0
/* return the number of tens of microseconds that have elapsed since
we were initialized */
bigtime_t now = real_time_clock_usecs();
now -= start;
now /= 10;
return (PRIntervalTime)now;
#endif
}
PRIntervalTime
_MD_interval_per_sec (void)
{
return 100000L;
}

View File

@ -0,0 +1,18 @@
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "MPL"); you may not use this file except in
# compliance with the MPL. You may obtain a copy of the MPL at
# http://www.mozilla.org/MPL/
#
# Software distributed under the MPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
# for the specific language governing rights and limitations under the
# MPL.
#
# This makefile appends to the variable OBJS the platform-dependent
# object modules that will be part of the nspr20 library.
include md/beos/bsrcs.mk
OBJS += $(MDCSRCS:%.c=md/beos/$(OBJDIR)/%.$(OBJ_SUFFIX))