[project @ 2002-02-13 08:48:06 by sof]
[ghc-hetmet.git] / ghc / rts / Capability.c
1 /* ---------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2001
4  *
5  * Capabilities
6  *
7  * The notion of a capability is used when operating in multi-threaded
8  * environments (which the SMP and Threads builds of the RTS do), to
9  * hold all the state an OS thread/task needs to run Haskell code:
10  * its STG registers, a pointer to its  TSO, a nursery etc. During
11  * STG execution, a pointer to the capabilitity is kept in a 
12  * register (BaseReg).
13  *
14  * Only in an SMP build will there be multiple capabilities, the threaded
15  * RTS and other non-threaded builds, there is one global capability,
16  * namely MainRegTable.
17  *
18  * 
19  * --------------------------------------------------------------------------*/
20 #include "PosixSource.h"
21 #include "Rts.h"
22 #include "Schedule.h"
23 #include "RtsUtils.h"
24 #include "Capability.h"
25
26 #if !defined(SMP)
27 Capability MainCapability;     /* for non-SMP, we have one global capability */
28 #endif
29
30 nat rts_n_free_capabilities;
31
32 static
33 void
34 initCapability( Capability *cap )
35 {
36     cap->f.stgChk0         = (F_)__stg_chk_0;
37     cap->f.stgChk1         = (F_)__stg_chk_1;
38     cap->f.stgGCEnter1     = (F_)__stg_gc_enter_1;
39     cap->f.stgUpdatePAP    = (F_)__stg_update_PAP;
40 }
41
42 #ifdef SMP
43 static void initCapabilities_(nat n);
44 #endif
45
46 /* 
47  */
48 void
49 initCapabilities()
50 {
51 #if defined(SMP)
52   initCapabilities_(RtsFlags.ParFlags.nNodes);
53 #else
54   initCapability(&MainCapability);
55   rts_n_free_capabilities = 1;
56 #endif
57
58   return;
59 }
60
61 /* Free capability list.
62  * Locks required: sched_mutex.
63  */
64 #if defined(SMP)
65 static Capability *free_capabilities; /* Available capabilities for running threads */
66 #endif
67
68 void grabCapability(Capability** cap)
69 {
70 #if !defined(SMP)
71   rts_n_free_capabilities = 0;
72   *cap = &MainCapability;
73 #else
74   *cap = free_capabilities;
75   free_capabilities = (*cap)->link;
76   rts_n_free_capabilities--;
77 #endif
78 }
79
80 /*
81  * Letting go of a capability
82  *
83  * Locks required: sched_mutex
84  */
85 void releaseCapability(Capability* cap
86 #if !defined(SMP)
87                        STG_UNUSED
88 #endif
89 )
90 {
91 #if defined(SMP)
92   cap->link = free_capabilities;
93   free_capabilities = cap;
94   rts_n_free_capabilities++;
95 #else
96   rts_n_free_capabilities = 1;
97 #endif
98
99 #if defined(RTS_SUPPORTS_THREADS)
100   /* Check to see whether a worker thread can be given
101      the go-ahead to return the result of an external call..*/
102   if (rts_n_waiting_workers > 0) {
103     /* The worker is responsible for grabbing the capability and
104      * decrementing the rts_n_returning_workers count
105      */
106     signalCondition(&returning_worker_cond);
107   } else if ( !EMPTY_RUN_QUEUE() ) {
108     /* Signal that work is available */
109     signalCondition(&thread_ready_cond);
110   }
111 #endif
112   return;
113 }
114
115 #if defined(SMP)
116 /* Allocate 'n' capabilities */
117 static void
118 initCapabilities_(nat n)
119 {
120   nat i;
121   Capability *cap, *prev;
122   cap  = NULL;
123   prev = NULL;
124   for (i = 0; i < n; i++) {
125     cap = stgMallocBytes(sizeof(Capability), "initCapabilities");
126     initCapability(cap);
127     cap->link = prev;
128     prev = cap;
129   }
130   free_capabilities = cap;
131   rts_n_free_capabilities = n;
132   IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Allocated %d capabilities\n", n_free_capabilities););
133 }
134 #endif /* SMP */
135