diff options
author | wtc%netscape.com <devnull@localhost> | 1999-01-25 23:52:00 +0000 |
---|---|---|
committer | wtc%netscape.com <devnull@localhost> | 1999-01-25 23:52:00 +0000 |
commit | 880ef565fedb4b848d0b8d8f8387ea7254a856a8 (patch) | |
tree | 4c8e91aab26a99821868b93c98fe5bb44f0ff4b5 | |
parent | cff6f10be0633a163f45e1001921a7760adcba0c (diff) | |
download | nspr-hg-880ef565fedb4b848d0b8d8f8387ea7254a856a8.tar.gz |
Added BeOS files contributed by Matthew Zahorik <maz@albany.net>.
-rw-r--r-- | pr/src/bthreads/Makefile | 31 | ||||
-rw-r--r-- | pr/src/bthreads/bsrcs.mk | 25 | ||||
-rw-r--r-- | pr/src/bthreads/btcmon.c | 405 | ||||
-rw-r--r-- | pr/src/bthreads/btcvar.c | 161 | ||||
-rw-r--r-- | pr/src/bthreads/btlocks.c | 89 | ||||
-rw-r--r-- | pr/src/bthreads/btmisc.c | 80 | ||||
-rw-r--r-- | pr/src/bthreads/btmon.c | 192 | ||||
-rw-r--r-- | pr/src/bthreads/btsem.c | 100 | ||||
-rw-r--r-- | pr/src/bthreads/btthread.c | 780 | ||||
-rw-r--r-- | pr/src/bthreads/objs.mk | 18 | ||||
-rw-r--r-- | pr/src/md/beos/Makefile | 28 | ||||
-rw-r--r-- | pr/src/md/beos/bcpu.c | 31 | ||||
-rw-r--r-- | pr/src/md/beos/beos.c | 240 | ||||
-rw-r--r-- | pr/src/md/beos/beos_errors.c | 1535 | ||||
-rw-r--r-- | pr/src/md/beos/bfile.c | 783 | ||||
-rw-r--r-- | pr/src/md/beos/bmemory.c | 18 | ||||
-rw-r--r-- | pr/src/md/beos/bmisc.c | 92 | ||||
-rw-r--r-- | pr/src/md/beos/bmmap.c | 39 | ||||
-rw-r--r-- | pr/src/md/beos/bnet.c | 648 | ||||
-rw-r--r-- | pr/src/md/beos/bproc.c | 39 | ||||
-rw-r--r-- | pr/src/md/beos/bseg.c | 35 | ||||
-rw-r--r-- | pr/src/md/beos/bsrcs.mk | 27 | ||||
-rw-r--r-- | pr/src/md/beos/btime.c | 51 | ||||
-rw-r--r-- | pr/src/md/beos/objs.mk | 18 |
24 files changed, 5465 insertions, 0 deletions
diff --git a/pr/src/bthreads/Makefile b/pr/src/bthreads/Makefile new file mode 100644 index 00000000..704b0445 --- /dev/null +++ b/pr/src/bthreads/Makefile @@ -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 + diff --git a/pr/src/bthreads/bsrcs.mk b/pr/src/bthreads/bsrcs.mk new file mode 100644 index 00000000..54a31d30 --- /dev/null +++ b/pr/src/bthreads/bsrcs.mk @@ -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) diff --git a/pr/src/bthreads/btcmon.c b/pr/src/bthreads/btcmon.c new file mode 100644 index 00000000..295a939c --- /dev/null +++ b/pr/src/bthreads/btcmon.c @@ -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); + } +} diff --git a/pr/src/bthreads/btcvar.c b/pr/src/bthreads/btcvar.c new file mode 100644 index 00000000..bdb594c5 --- /dev/null +++ b/pr/src/bthreads/btcvar.c @@ -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; +} diff --git a/pr/src/bthreads/btlocks.c b/pr/src/bthreads/btlocks.c new file mode 100644 index 00000000..d7f90694 --- /dev/null +++ b/pr/src/bthreads/btlocks.c @@ -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; +} diff --git a/pr/src/bthreads/btmisc.c b/pr/src/bthreads/btmisc.c new file mode 100644 index 00000000..f0ec4807 --- /dev/null +++ b/pr/src/bthreads/btmisc.c @@ -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; +} diff --git a/pr/src/bthreads/btmon.c b/pr/src/bthreads/btmon.c new file mode 100644 index 00000000..81e7ed0d --- /dev/null +++ b/pr/src/bthreads/btmon.c @@ -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 ); +} + diff --git a/pr/src/bthreads/btsem.c b/pr/src/bthreads/btsem.c new file mode 100644 index 00000000..3e7cbe8a --- /dev/null +++ b/pr/src/bthreads/btsem.c @@ -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; +} diff --git a/pr/src/bthreads/btthread.c b/pr/src/bthreads/btthread.c new file mode 100644 index 00000000..5f5e6564 --- /dev/null +++ b/pr/src/bthreads/btthread.c @@ -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); +} diff --git a/pr/src/bthreads/objs.mk b/pr/src/bthreads/objs.mk new file mode 100644 index 00000000..01f2b63d --- /dev/null +++ b/pr/src/bthreads/objs.mk @@ -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)) diff --git a/pr/src/md/beos/Makefile b/pr/src/md/beos/Makefile new file mode 100644 index 00000000..ef9b5e6c --- /dev/null +++ b/pr/src/md/beos/Makefile @@ -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 diff --git a/pr/src/md/beos/bcpu.c b/pr/src/md/beos/bcpu.c new file mode 100644 index 00000000..ca29cf8e --- /dev/null +++ b/pr/src/md/beos/bcpu.c @@ -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); diff --git a/pr/src/md/beos/beos.c b/pr/src/md/beos/beos.c new file mode 100644 index 00000000..73c7a4e1 --- /dev/null +++ b/pr/src/md/beos/beos.c @@ -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 diff --git a/pr/src/md/beos/beos_errors.c b/pr/src/md/beos/beos_errors.c new file mode 100644 index 00000000..e47b1ce9 --- /dev/null +++ b/pr/src/md/beos/beos_errors.c @@ -0,0 +1,1535 @@ +/* -*- 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 "prtypes.h" +#include "md/_unix_errors.h" +#include "prerror.h" +#include <errno.h> + +void _MD_unix_map_opendir_error(int err) +{ + switch (err) { + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_closedir_error(int err) +{ + switch (err) { + case EINVAL: + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_readdir_error(int err) +{ + + switch (err) { + case ENOENT: + PR_SetError(PR_NO_MORE_FILES_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef IRIX +#ifdef IRIX5_3 +#else + case EDIRCORRUPTED: + PR_SetError(PR_DIRECTORY_CORRUPTED_ERROR, err); + break; +#endif +#endif +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_IO_ERROR, err); + break; +#ifdef EBADMSG + case EBADMSG: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_unlink_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EPERM: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_stat_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ETIMEDOUT: +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: +#endif + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_fstat_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ETIMEDOUT: +#ifdef ENOLINK + case ENOLINK: +#endif + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_rename_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif + case EEXIST: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + case EXDEV: + PR_SetError(PR_NOT_SAME_DEVICE_ERROR, err); + break; + case EMLINK: + PR_SetError(PR_MAX_DIRECTORY_ENTRIES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_access_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_mkdir_error(int err) +{ + switch (err) { + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case EMLINK: + PR_SetError(PR_MAX_DIRECTORY_ENTRIES_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_rmdir_error(int err) +{ + + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_read_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef EBADMSG + case EBADMSG: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_write_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EFBIG: + PR_SetError(PR_FILE_TOO_BIG_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case ERANGE: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_lseek_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ESPIPE: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_fsync_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_close_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socket_error(int err) +{ + switch (err) { + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socketavailable_error(int err) +{ + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); +} + +void _MD_unix_map_recv_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_recvfrom_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_send_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EMSGSIZE: +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif /* !defined(SCO) */ + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_sendto_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EMSGSIZE: +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif /* !defined(SCO) */ + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_writev_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_accept_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EOPNOTSUPP: +#endif + case ENODEV: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif +#ifdef EPROTO + case EPROTO: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_connect_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EINPROGRESS: + PR_SetError(PR_IN_PROGRESS_ERROR, err); + break; + case EALREADY: + PR_SetError(PR_ALREADY_INITIATED_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case ENETUNREACH: + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + /* + * UNIX domain sockets are not supported in NSPR + */ + case EACCES: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EIO: +#if defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * On some platforms, if we connect to a port on + * the local host (the loopback address) that no + * process is listening on, we get EIO instead + * of ECONNREFUSED. + */ + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); +#else + PR_SetError(PR_IO_ERROR, err); +#endif + break; + case ELOOP: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EPROTOTYPE: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_bind_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + /* + * UNIX domain sockets are not supported in NSPR + */ + case EIO: + case EISDIR: + case ELOOP: + case ENOENT: + case ENOTDIR: + case EROFS: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_listen_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_shutdown_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socketpair_error(int err) +{ + switch (err) { + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EAFNOSUPPORT: + case EPROTONOSUPPORT: +#if !defined(BEOS) + case EOPNOTSUPP: +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getsockname_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getpeername_error(int err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getsockopt_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_setsockopt_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_open_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EAGAIN: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ENODEV: + case ENOENT: + case ENXIO: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EPERM: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ETIMEDOUT: +#if !defined(OSF1) && !defined(FREEBSD) && !defined(BSDI) && !defined(RHAPSODY) && !defined(BEOS) + case EMULTIHOP: + case ENOLINK: +#endif + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_mmap_error(int err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EAGAIN: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_gethostname_error(int err) +{ + switch (err) { + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_select_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_poll_error(int err) +{ + PRErrorCode prerror; + switch (err) { + case EAGAIN: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case EFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, err); +} + +void _MD_unix_map_flock_error(int err) +{ + switch (err) { + case EBADF: + case EINVAL: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EWOULDBLOCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_lockf_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EACCES: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case EDEADLK: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +#ifdef HPUX11 +void _MD_hpux_map_sendfile_error(int oserror) +{ + PRErrorCode prerror; + + switch (oserror) { + case ENOTSOCK: + prerror = PR_NOT_SOCKET_ERROR; + break; + case EFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; + case ENOBUFS: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case ENOTCONN: + prerror = PR_NOT_CONNECTED_ERROR; + break; + case EPIPE: + prerror = PR_CONNECT_RESET_ERROR; + break; + case ENOMEM: + prerror = PR_OUT_OF_MEMORY_ERROR; + break; + case EOPNOTSUPP: + prerror = PR_NOT_TCP_SOCKET_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, oserror); +} +#endif /* HPUX11 */ diff --git a/pr/src/md/beos/bfile.c b/pr/src/md/beos/bfile.c new file mode 100644 index 00000000..e22ec4c0 --- /dev/null +++ b/pr/src/md/beos/bfile.c @@ -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( ¤tConnectList[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, + ¤tConnectList[i].addr, + ¤tConnectList[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; +} + diff --git a/pr/src/md/beos/bmemory.c b/pr/src/md/beos/bmemory.c new file mode 100644 index 00000000..c14696d8 --- /dev/null +++ b/pr/src/md/beos/bmemory.c @@ -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); diff --git a/pr/src/md/beos/bmisc.c b/pr/src/md/beos/bmisc.c new file mode 100644 index 00000000..977ed68d --- /dev/null +++ b/pr/src/md/beos/bmisc.c @@ -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; +} diff --git a/pr/src/md/beos/bmmap.c b/pr/src/md/beos/bmmap.c new file mode 100644 index 00000000..572b25fc --- /dev/null +++ b/pr/src/md/beos/bmmap.c @@ -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; +} diff --git a/pr/src/md/beos/bnet.c b/pr/src/md/beos/bnet.c new file mode 100644 index 00000000..069f5adb --- /dev/null +++ b/pr/src/md/beos/bnet.c @@ -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 */ +} diff --git a/pr/src/md/beos/bproc.c b/pr/src/md/beos/bproc.c new file mode 100644 index 00000000..01e5236d --- /dev/null +++ b/pr/src/md/beos/bproc.c @@ -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; +} diff --git a/pr/src/md/beos/bseg.c b/pr/src/md/beos/bseg.c new file mode 100644 index 00000000..36ef7448 --- /dev/null +++ b/pr/src/md/beos/bseg.c @@ -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) +{ +} diff --git a/pr/src/md/beos/bsrcs.mk b/pr/src/md/beos/bsrcs.mk new file mode 100644 index 00000000..1851e20b --- /dev/null +++ b/pr/src/md/beos/bsrcs.mk @@ -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) diff --git a/pr/src/md/beos/btime.c b/pr/src/md/beos/btime.c new file mode 100644 index 00000000..a80a1d61 --- /dev/null +++ b/pr/src/md/beos/btime.c @@ -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; +} diff --git a/pr/src/md/beos/objs.mk b/pr/src/md/beos/objs.mk new file mode 100644 index 00000000..fcca42fd --- /dev/null +++ b/pr/src/md/beos/objs.mk @@ -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)) |