Capability.h 10.3 KB
Newer Older
sof's avatar
sof committed
1
2
/* ---------------------------------------------------------------------------
 *
3
 * (c) The GHC Team, 2001-2006
sof's avatar
sof committed
4
5
6
7
 *
 * Capabilities
 *
 * The notion of a capability is used when operating in multi-threaded
8
 * environments (which the THREADED_RTS build of the RTS does), to
sof's avatar
sof committed
9
10
11
12
13
 * 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).
 *
14
15
16
 * Only in an THREADED_RTS build will there be multiple capabilities,
 * in the non-threaded builds there is one global capability, namely
 * MainCapability.
sof's avatar
sof committed
17
18
19
20
21
 *
 * This header file contains the functions for working with capabilities.
 * (the main, and only, consumer of this interface is the scheduler).
 * 
 * --------------------------------------------------------------------------*/
22

23
24
#ifndef CAPABILITY_H
#define CAPABILITY_H
sof's avatar
sof committed
25

26
#include "RtsFlags.h"
27
#include "Task.h"
28
#include "Sparks.h"
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

struct Capability_ {
    // State required by the STG virtual machine when running Haskell
    // code.  During STG execution, the BaseReg register always points
    // to the StgRegTable of the current Capability (&cap->r).
    StgFunTable f;
    StgRegTable r;

    nat no;  // capability number.

    // The Task currently holding this Capability.  This task has
    // exclusive access to the contents of this Capability (apart from
    // returning_tasks_hd/returning_tasks_tl).
    // Locks required: cap->lock.
    Task *running_task;

    // true if this Capability is running Haskell code, used for
    // catching unsafe call-ins.
    rtsBool in_haskell;

    // The run queue.  The Task owning this Capability has exclusive
    // access to its run queue, so can wake up threads without
    // taking a lock, and the common path through the scheduler is
    // also lock-free.
    StgTSO *run_queue_hd;
    StgTSO *run_queue_tl;

    // Tasks currently making safe foreign calls.  Doubly-linked.
    // When returning, a task first acquires the Capability before
    // removing itself from this list, so that the GC can find all
    // the suspended TSOs easily.  Hence, when migrating a Task from
    // the returning_tasks list, we must also migrate its entry from
    // this list.
    Task *suspended_ccalling_tasks;

64
65
66
67
68
69
    // One mutable list per generation, so we don't need to take any
    // locks when updating an old-generation thunk.  These
    // mini-mut-lists are moved onto the respective gen->mut_list at
    // each GC.
    bdescr **mut_lists;

70
71
72
73
    // Context switch flag. We used to have one global flag, now one 
    // per capability. Locks required  : none (conflicts are harmless)
    int context_switch;

74
75
76
77
#if defined(THREADED_RTS)
    // Worker Tasks waiting in the wings.  Singly-linked.
    Task *spare_workers;

78
    // This lock protects running_task, returning_tasks_{hd,tl}, wakeup_queue.
79
80
81
82
83
84
85
86
87
    Mutex lock;

    // Tasks waiting to return from a foreign call, or waiting to make
    // a new call-in using this Capability (NULL if empty).
    // NB. this field needs to be modified by tasks other than the
    // running_task, so it requires cap->lock to modify.  A task can
    // check whether it is NULL without taking the lock, however.
    Task *returning_tasks_hd; // Singly-linked, with head/tail
    Task *returning_tasks_tl;
88
89
90
91
92
93

    // A list of threads to append to this Capability's run queue at
    // the earliest opportunity.  These are threads that have been
    // woken up by another Capability.
    StgTSO *wakeup_queue_hd;
    StgTSO *wakeup_queue_tl;
94
95
96
97
98
99
100

    SparkPool *sparks;

    // Stats on spark creation/conversion
    nat sparks_created;
    nat sparks_converted;
    nat sparks_pruned;
101
#endif
102
103

    // Per-capability STM-related data
tharris@microsoft.com's avatar
tharris@microsoft.com committed
104
105
    StgTVarWatchQueue *free_tvar_watch_queues;
    StgInvariantCheckQueue *free_invariant_check_queues;
106
107
108
    StgTRecChunk *free_trec_chunks;
    StgTRecHeader *free_trec_headers;
    nat transaction_tokens;
109
110
111
112
} // typedef Capability is defined in RtsAPI.h
  // Capabilities are stored in an array, so make sure that adjacent
  // Capabilities don't share any cache-lines:
  ATTRIBUTE_ALIGNED(64);
113

114

sof's avatar
sof committed
115
116
117
118
119
120
#if defined(THREADED_RTS)
#define ASSERT_TASK_ID(task) ASSERT(task->id == osThreadId())
#else
#define ASSERT_TASK_ID(task) /*empty*/
#endif

121
// These properties should be true when a Task is holding a Capability
122
#define ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task)			\
123
124
  ASSERT(cap->running_task != NULL && cap->running_task == task);	\
  ASSERT(task->cap == cap);						\
125
126
127
128
129
130
131
132
133
134
135
  ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task)

// Sometimes a Task holds a Capability, but the Task is not associated
// with that Capability (ie. task->cap != cap).  This happens when
// (a) a Task holds multiple Capabilities, and (b) when the current
// Task is bound, its thread has just blocked, and it may have been
// moved to another Capability.
#define ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task)	\
  ASSERT(cap->run_queue_hd == END_TSO_QUEUE ?		\
	    cap->run_queue_tl == END_TSO_QUEUE : 1);	\
  ASSERT(myTask() == task);				\
sof's avatar
sof committed
136
  ASSERT_TASK_ID(task);
137

138
139
140
141
142
143
144
// Converts a *StgRegTable into a *Capability.
//
INLINE_HEADER Capability *
regTableToCapability (StgRegTable *reg)
{
    return (Capability *)((void *)((unsigned char*)reg - sizeof(StgFunTable)));
}
145

146
// Initialise the available capabilities.
147
//
148
149
150
151
152
153
154
155
156
void initCapabilities (void);

// Release a capability.  This is called by a Task that is exiting
// Haskell to make a foreign call, or in various other cases when we
// want to relinquish a Capability that we currently hold.
//
// ASSUMES: cap->running_task is the current Task.
//
#if defined(THREADED_RTS)
157
158
159
160
void releaseCapability           (Capability* cap);
void releaseAndWakeupCapability  (Capability* cap);
void releaseCapability_ (Capability* cap, rtsBool always_wakeup); 
// assumes cap->lock is held
161
162
163
#else
// releaseCapability() is empty in non-threaded RTS
INLINE_HEADER void releaseCapability  (Capability* cap STG_UNUSED) {};
164
165
166
INLINE_HEADER void releaseAndWakeupCapability  (Capability* cap STG_UNUSED) {};
INLINE_HEADER void releaseCapability_ (Capability* cap STG_UNUSED, 
                                       rtsBool always_wakeup STG_UNUSED) {};
167
#endif
168

169
170
#if !IN_STG_CODE
// one global capability
171
172
173
174
extern Capability MainCapability; 
#endif

// Array of all the capabilities
175
//
176
177
extern nat n_capabilities;
extern Capability *capabilities;
178

179
180
// The Capability that was last free.  Used as a good guess for where
// to assign new threads.
181
//
182
extern Capability *last_free_capability;
183

184
185
186
// GC indicator, in scope for the scheduler
extern volatile StgWord waiting_for_gc;

187
188
189
190
191
192
193
194
195
196
// Acquires a capability at a return point.  If *cap is non-NULL, then
// this is taken as a preference for the Capability we wish to
// acquire.
//
// OS threads waiting in this function get priority over those waiting
// in waitForCapability().
//
// On return, *cap is non-NULL, and points to the Capability acquired.
//
void waitForReturnCapability (Capability **cap/*in/out*/, Task *task);
197

198
199
INLINE_HEADER void recordMutableCap (StgClosure *p, Capability *cap, nat gen);

200
#if defined(THREADED_RTS)
201

202
203
204
205
206
207
208
209
210
// 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
211
// current task should then re-acquire it using waitForCapability().
212
//
213
void yieldCapability (Capability** pCap, Task *task);
214
215
216
217
218

// Acquires a capability for doing some work.
//
// On return: pCap points to the capability.
//
219
void waitForCapability (Task *task, Mutex *mutex, Capability **pCap);
220

221
222
223
// Wakes up a thread on a Capability (probably a different Capability
// from the one held by the current Task).
//
224
225
void wakeupThreadOnCapability (Capability *my_cap, Capability *other_cap,
                               StgTSO *tso);
226

227
228
// Wakes up a worker thread on just one Capability, used when we
// need to service some global event.
229
//
230
void prodOneCapability (void);
231

232
// Similar to prodOneCapability(), but prods all of them.
233
//
234
void prodAllCapabilities (void);
sof's avatar
sof committed
235

236
237
238
// Waits for a capability to drain of runnable threads and workers,
// and then acquires it.  Used at shutdown time.
//
239
void shutdownCapability (Capability *cap, Task *task, rtsBool wait_foreign);
sof's avatar
sof committed
240

241
242
243
244
// Attempt to gain control of a Capability if it is free.
//
rtsBool tryGrabCapability (Capability *cap, Task *task);

245
246
// Try to steal a spark from other Capabilities
//
247
248
249
250
251
StgClosure *stealWork (Capability *cap);

// True if any capabilities have sparks
//
rtsBool anySparks (void);
252
253
254
255
256

INLINE_HEADER rtsBool emptySparkPoolCap (Capability *cap);
INLINE_HEADER nat     sparkPoolSizeCap  (Capability *cap);
INLINE_HEADER void    discardSparksCap  (Capability *cap);

257
#else // !THREADED_RTS
258
259
260
261

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

264
#endif /* !THREADED_RTS */
sof's avatar
sof committed
265

266
267
268
// cause all capabilities to context switch as soon as possible.
void setContextSwitches(void);

269
270
// Free all capabilities
void freeCapabilities (void);
Ian Lynagh's avatar
Ian Lynagh committed
271

272
// FOr the GC:
273
274
void markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta, 
                           rtsBool prune_sparks);
275
void markCapabilities (evac_fn evac, void *user);
276
void traverseSparkQueues (evac_fn evac, void *user);
277

278
279
280
281
282
283
284
285
286
/* -----------------------------------------------------------------------------
 * INLINE functions... private below here
 * -------------------------------------------------------------------------- */

INLINE_HEADER void
recordMutableCap (StgClosure *p, Capability *cap, nat gen)
{
    bdescr *bd;

287
288
    // We must own this Capability in order to modify its mutable list.
    ASSERT(cap->running_task == myTask());
289
290
291
292
293
294
295
296
297
298
299
    bd = cap->mut_lists[gen];
    if (bd->free >= bd->start + BLOCK_SIZE_W) {
	bdescr *new_bd;
	new_bd = allocBlock_lock();
	new_bd->link = bd;
	bd = new_bd;
	cap->mut_lists[gen] = bd;
    }
    *bd->free++ = (StgWord)p;
}

300
301
302
303
304
305
306
307
308
309
310
311
312
313
#if defined(THREADED_RTS)
INLINE_HEADER rtsBool
emptySparkPoolCap (Capability *cap) 
{ return looksEmpty(cap->sparks); }

INLINE_HEADER nat
sparkPoolSizeCap (Capability *cap) 
{ return sparkPoolSize(cap->sparks); }

INLINE_HEADER void
discardSparksCap (Capability *cap) 
{ return discardSparks(cap->sparks); }
#endif

314
#endif /* CAPABILITY_H */