summaryrefslogtreecommitdiff
path: root/ghc/rts/Capability.h
blob: e6150351876d9a56da0b8e5986808fe942927a59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* ---------------------------------------------------------------------------
 *
 * (c) The GHC Team, 2001-2003
 *
 * Capabilities
 *
 * The notion of a capability is used when operating in multi-threaded
 * environments (which the SMP and Threads builds of the RTS do), to
 * hold all the state an OS thread/task needs to run Haskell code:
 * its STG registers, a pointer to its  TSO, a nursery etc. During
 * STG execution, a pointer to the capabilitity is kept in a 
 * register (BaseReg).
 *
 * Only in an SMP build will there be multiple capabilities, the threaded
 * RTS and other non-threaded builds, there is one global capability,
 * namely MainRegTable.
 *
 * This header file contains the functions for working with capabilities.
 * (the main, and only, consumer of this interface is the scheduler).
 * 
 * --------------------------------------------------------------------------*/

#ifndef __CAPABILITY_H__
#define __CAPABILITY_H__

// Initialised the available capabilities.
//
extern void initCapabilities( void );

// Releases a capability
//
extern void releaseCapability( Capability* cap );

// Signal that a thread has become runnable
//
extern void threadRunnable ( void );

#ifdef RTS_SUPPORTS_THREADS
// Gives up the current capability IFF there is a higher-priority
// thread waiting for it.  This happens in one of two ways:
//
//   (a) we are passing the capability to another OS thread, so
//       that it can run a bound Haskell thread, or
//
//   (b) there is an OS thread waiting to return from a foreign call
//
// On return: *pCap is NULL if the capability was released.  The
// current worker thread should then re-acquire it using
// waitForCapability().
//
extern void yieldCapability( Capability **pCap );

// Acquires a capability for doing some work.
//
// If the current OS thread is bound to a particular Haskell thread,
// then pThreadCond points to a condition variable for waking up this
// OS thread when its Haskell thread is ready to run.
//
// On return: pCap points to the capability.
extern void waitForCapability( Mutex* pMutex, Capability** pCap, 
			       Condition *pThreadCond );

// Acquires a capability at a return point.  
//
// OS threads waiting in this function get priority over those waiting
// in waitForWorkCapability().
//
// On return: pCap points to the capability.
extern void waitForReturnCapability(Mutex* pMutex, Capability** pCap);

// Signals that the next time a capability becomes free, it should
// be transfered to a particular OS thread, identified by the
// condition variable pTargetThreadCond.
//
extern void passCapability(Condition *pTargetThreadCond);

// Signals that the next time a capability becomes free, it should
// be transfered to an ordinary worker thread.
//
extern void passCapabilityToWorker( void );

extern nat rts_n_free_capabilities;  
/* number of worker threads waiting for a return capability
 */
extern nat rts_n_waiting_workers;

static inline rtsBool needToYieldToReturningWorker(void)
{
	return rts_n_waiting_workers > 0;
}

static inline nat getFreeCapabilities (void)
{
  return rts_n_free_capabilities;
}

static inline rtsBool noCapabilities (void)
{
  return (rts_n_free_capabilities == 0);
}

static inline rtsBool allFreeCapabilities (void)
{
  return (rts_n_free_capabilities == 1);
}

#else // !RTS_SUPPORTS_THREADS

// Grab a capability.  (Only in the non-threaded RTS; in the threaded
// RTS one of the waitFor*Capability() functions must be used).
//
extern void grabCapability( Capability **pCap );

#endif // !RTS_SUPPORTS_THREADS

#endif /* __CAPABILITY_H__ */