diff options
| author | simonmar <unknown> | 2005-10-21 14:02:18 +0000 |
|---|---|---|
| committer | simonmar <unknown> | 2005-10-21 14:02:18 +0000 |
| commit | 03a9ff01812afc81eb5236fd3063cbec44cf469e (patch) | |
| tree | e02ce9ff95e7ed47b811ec2014fa43027d9a175f /ghc/includes/OSThreads.h | |
| parent | 63e8af080a7e779a48e812e6caa9ea519b046260 (diff) | |
| download | haskell-03a9ff01812afc81eb5236fd3063cbec44cf469e.tar.gz | |
[project @ 2005-10-21 14:02:17 by simonmar]
Big re-hash of the threaded/SMP runtime
This is a significant reworking of the threaded and SMP parts of
the runtime. There are two overall goals here:
- To push down the scheduler lock, reducing contention and allowing
more parts of the system to run without locks. In particular,
the scheduler does not require a lock any more in the common case.
- To improve affinity, so that running Haskell threads stick to the
same OS threads as much as possible.
At this point we have the basic structure working, but there are some
pieces missing. I believe it's reasonably stable - the important
parts of the testsuite pass in all the (normal,threaded,SMP) ways.
In more detail:
- Each capability now has a run queue, instead of one global run
queue. The Capability and Task APIs have been completely
rewritten; see Capability.h and Task.h for the details.
- Each capability has its own pool of worker Tasks. Hence, Haskell
threads on a Capability's run queue will run on the same worker
Task(s). As long as the OS is doing something reasonable, this
should mean they usually stick to the same CPU. Another way to
look at this is that we're assuming each Capability is associated
with a fixed CPU.
- What used to be StgMainThread is now part of the Task structure.
Every OS thread in the runtime has an associated Task, and it
can ask for its current Task at any time with myTask().
- removed RTS_SUPPORTS_THREADS symbol, use THREADED_RTS instead
(it is now defined for SMP too).
- The RtsAPI has had to change; we must explicitly pass a Capability
around now. The previous interface assumed some global state.
SchedAPI has also changed a lot.
- The OSThreads API now supports thread-local storage, used to
implement myTask(), although it could be done more efficiently
using gcc's __thread extension when available.
- I've moved some POSIX-specific stuff into the posix subdirectory,
moving in the direction of separating out platform-specific
implementations.
- lots of lock-debugging and assertions in the runtime. In particular,
when DEBUG is on, we catch multiple ACQUIRE_LOCK()s, and there is
also an ASSERT_LOCK_HELD() call.
What's missing so far:
- I have almost certainly broken the Win32 build, will fix soon.
- any kind of thread migration or load balancing. This is high up
the agenda, though.
- various performance tweaks to do
- throwTo and forkProcess still do not work in SMP mode
Diffstat (limited to 'ghc/includes/OSThreads.h')
| -rw-r--r-- | ghc/includes/OSThreads.h | 76 |
1 files changed, 69 insertions, 7 deletions
diff --git a/ghc/includes/OSThreads.h b/ghc/includes/OSThreads.h index a065f7a408..7579f880cd 100644 --- a/ghc/includes/OSThreads.h +++ b/ghc/includes/OSThreads.h @@ -10,27 +10,63 @@ #ifndef __OSTHREADS_H__ #define __OSTHREADS_H__ -#if defined(RTS_SUPPORTS_THREADS) /* to the end */ +#if defined(THREADED_RTS) /* to the end */ # if defined(HAVE_PTHREAD_H) && !defined(WANT_NATIVE_WIN32_THREADS) -# include <pthread.h> + +#include <pthread.h> + typedef pthread_cond_t Condition; typedef pthread_mutex_t Mutex; typedef pthread_t OSThreadId; +typedef pthread_key_t ThreadLocalKey; + +#define OSThreadProcAttr /* nothing */ #define INIT_MUTEX_VAR PTHREAD_MUTEX_INITIALIZER #define INIT_COND_VAR PTHREAD_COND_INITIALIZER #ifdef LOCK_DEBUG + #define ACQUIRE_LOCK(mutex) \ debugBelch("ACQUIRE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \ pthread_mutex_lock(mutex) #define RELEASE_LOCK(mutex) \ debugBelch("RELEASE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \ pthread_mutex_unlock(mutex) +#define ASSERT_LOCK_HELD(mutex) /* nothing */ + +#elif defined(DEBUG) && defined(linux_HOST_OS) +#include <errno.h> +/* + * On Linux, we can use extensions to determine whether we already + * hold a lock or not, which is useful for debugging. + */ +#define ACQUIRE_LOCK(mutex) \ + if (pthread_mutex_lock(mutex) == EDEADLK) { \ + barf("multiple ACQUIRE_LOCK: %s %d", __FILE__,__LINE__); \ + } +#define RELEASE_LOCK(mutex) \ + if (pthread_mutex_unlock(mutex) != 0) { \ + barf("RELEASE_LOCK: I do not own this lock: %s %d", __FILE__,__LINE__); \ + } + +#define ASSERT_LOCK_HELD(mutex) ASSERT(pthread_mutex_lock(mutex) == EDEADLK) + +#define ASSERT_LOCK_NOTHELD(mutex) \ + if (pthread_mutex_lock(mutex) != EDEADLK) { \ + pthread_mutex_unlock(mutex); \ + } else { \ + ASSERT(0); \ + } + + #else + #define ACQUIRE_LOCK(mutex) pthread_mutex_lock(mutex) #define RELEASE_LOCK(mutex) pthread_mutex_unlock(mutex) +#define ASSERT_LOCK_HELD(mutex) /* nothing */ + #endif # elif defined(HAVE_WINDOWS_H) @@ -39,6 +75,9 @@ typedef pthread_t OSThreadId; typedef HANDLE Condition; typedef HANDLE Mutex; typedef DWORD OSThreadId; +typedef DWORD ThreadLocalKey; + +#define OSThreadProcAttr __stdcall #define INIT_MUTEX_VAR 0 #define INIT_COND_VAR 0 @@ -59,10 +98,27 @@ RELEASE_LOCK(Mutex *mutex) } } +#define ASSERT_LOCK_HELD(mutex) /* nothing */ + # else # error "Threads not supported" # endif +// +// General thread operations +// +extern OSThreadId osThreadId ( void ); +extern void shutdownThread ( void ); +extern void yieldThread ( void ); + +typedef void OSThreadProcAttr OSThreadProc(void *); + +extern int createOSThread ( OSThreadId* tid, + OSThreadProc *startProc, void *param); + +// +// Condition Variables +// extern void initCondition ( Condition* pCond ); extern void closeCondition ( Condition* pCond ); extern rtsBool broadcastCondition ( Condition* pCond ); @@ -70,17 +126,23 @@ extern rtsBool signalCondition ( Condition* pCond ); extern rtsBool waitCondition ( Condition* pCond, Mutex* pMut ); +// +// Mutexes +// extern void initMutex ( Mutex* pMut ); -extern OSThreadId osThreadId ( void ); -extern void shutdownThread ( void ); -extern void yieldThread ( void ); -extern int createOSThread ( OSThreadId* tid, - void (*startProc)(void) ); +// +// Thread-local storage +// +void newThreadLocalKey (ThreadLocalKey *key); +void *getThreadLocalVar (ThreadLocalKey *key); +void setThreadLocalVar (ThreadLocalKey *key, void *value); + #else #define ACQUIRE_LOCK(l) #define RELEASE_LOCK(l) +#define ASSERT_LOCK_HELD(l) #endif /* defined(RTS_SUPPORTS_THREADS) */ |
