source: src/libcfa/concurrency/monitor.c@ 154fdc8

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 154fdc8 was 5ea06d6, checked in by Thierry Delisle <tdelisle@…>, 8 years ago

Prototype of multi monitor internal scheduling

  • Property mode set to 100644
File size: 6.5 KB
Line 
1// -*- Mode: CFA -*-
2//
3// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
4//
5// The contents of this file are covered under the licence agreement in the
6// file "LICENCE" distributed with Cforall.
7//
8// monitor_desc.c --
9//
10// Author : Thierry Delisle
11// Created On : Thd Feb 23 12:27:26 2017
12// Last Modified By : Thierry Delisle
13// Last Modified On : --
14// Update Count : 0
15//
16
17#include "monitor"
18
19#include "kernel_private.h"
20#include "libhdr.h"
21
22void set_owner( monitor_desc * this, thread_desc * owner ) {
23 //Pass the monitor appropriately
24 this->owner = owner;
25
26 //We are passing the monitor to someone else, which means recursion level is not 0
27 this->recursion = owner ? 1 : 0;
28}
29
30extern "C" {
31 void __enter_monitor_desc(monitor_desc * this, monitor_desc * leader) {
32 lock( &this->lock );
33 thread_desc * thrd = this_thread();
34
35 //Update the stack owner
36 this->stack_owner = leader;
37
38 if( !this->owner ) {
39 //No one has the monitor, just take it
40 this->owner = thrd;
41 this->recursion = 1;
42 }
43 else if( this->owner == thrd) {
44 //We already have the monitor, just not how many times we took it
45 assert( this->recursion > 0 );
46 this->recursion += 1;
47 }
48 else {
49 //Some one else has the monitor, wait in line for it
50 append( &this->entry_queue, thrd );
51 ScheduleInternal( &this->lock );
52
53 //ScheduleInternal will unlock spinlock, no need to unlock ourselves
54 return;
55 }
56
57 unlock( &this->lock );
58 return;
59 }
60
61 // leave pseudo code :
62 // decrement level
63 // leve == 0 ?
64 // no : done
65 // yes :
66 // signal stack empty ?
67 // has leader :
68 // bulk acquiring means we don't own the signal stack
69 // ignore it but don't release the monitor
70 // yes :
71 // next in entry queue is new owner
72 // no :
73 // top of the signal stack is the owner
74 // context switch to him right away
75 //
76 void __leave_monitor_desc(monitor_desc * this, monitor_desc * leader) {
77 lock( &this->lock );
78
79 thread_desc * thrd = this_thread();
80 assert( thrd == this->owner || this->stack_owner );
81
82 //Leaving a recursion level, decrement the counter
83 this->recursion -= 1;
84
85 //If we haven't left the last level of recursion
86 //it means we don't need to do anything
87 if( this->recursion != 0) {
88 this->stack_owner = leader;
89 unlock( &this->lock );
90 return;
91 }
92
93 //If we don't own the signal stack then just leave it to the owner
94 if( this->stack_owner ) {
95 this->stack_owner = leader;
96 unlock( &this->lock );
97 return;
98 }
99
100 //We are the stack owner and have left the last recursion level.
101 //We are in charge of passing the monitor
102 thread_desc * new_owner = 0;
103
104 //Check the signaller stack
105 new_owner = pop( &this->signal_stack );
106 if( new_owner ) {
107 //The signaller stack is not empty,
108 //transfer control immediately
109 set_owner( this, new_owner );
110 this->stack_owner = leader;
111 ScheduleInternal( &this->lock, new_owner );
112 return;
113 }
114
115 // No signaller thread
116 // Get the next thread in the entry_queue
117 new_owner = pop_head( &this->entry_queue );
118 set_owner( this, new_owner );
119
120 //Update the stack owner
121 this->stack_owner = leader;
122
123 //We can now let other threads in safely
124 unlock( &this->lock );
125
126 //We need to wake-up the thread
127 ScheduleThread( new_owner );
128 }
129}
130
131static inline void enter(monitor_desc ** monitors, int count) {
132 __enter_monitor_desc( monitors[0], NULL );
133 for(int i = 1; i < count; i++) {
134 __enter_monitor_desc( monitors[i], monitors[0] );
135 }
136}
137
138static inline void leave(monitor_desc ** monitors, int count) {
139 __leave_monitor_desc( monitors[0], NULL );
140 for(int i = count - 1; i >= 0; i--) {
141 __leave_monitor_desc( monitors[i], monitors[0] );
142 }
143}
144
145void ?{}( monitor_guard_t * this, monitor_desc ** m, int count ) {
146 this->m = m;
147 this->count = count;
148 qsort(this->m, count);
149 enter( this->m, this->count );
150
151 this->prev_mntrs = this_thread()->current_monitors;
152 this->prev_count = this_thread()->current_monitor_count;
153
154 this_thread()->current_monitors = m;
155 this_thread()->current_monitor_count = count;
156}
157
158void ^?{}( monitor_guard_t * this ) {
159 leave( this->m, this->count );
160
161 this_thread()->current_monitors = this->prev_mntrs;
162 this_thread()->current_monitor_count = this->prev_count;
163}
164
165//-----------------------------------------------------------------------------
166// Internal scheduling
167void wait( condition * this ) {
168 // LIB_DEBUG_FPRINTF("Waiting\n");
169 thread_desc * this_thrd = this_thread();
170
171 if( !this->monitors ) {
172 this->monitors = this_thrd->current_monitors;
173 this->monitor_count = this_thrd->current_monitor_count;
174 }
175
176 unsigned short count = this->monitor_count;
177
178 //Check that everything is as expected
179 assert( this->monitors != NULL );
180 assert( this->monitor_count != 0 );
181
182 unsigned int recursions[ count ]; //Save the current recursion levels to restore them later
183 spinlock * locks [ count ]; //We need to pass-in an array of locks to ScheduleInternal
184
185 // LIB_DEBUG_FPRINTF("Getting ready to wait\n");
186
187 //Loop on all the monitors and release the owner
188 for( unsigned int i = 0; i < count; i++ ) {
189 monitor_desc * cur = this->monitors[i];
190
191 assert( cur );
192
193 // LIB_DEBUG_FPRINTF("cur %p lock %p\n", cur, &cur->lock);
194
195 //Store the locks for later
196 locks[i] = &cur->lock;
197
198 //Protect the monitors
199 lock( locks[i] );
200 {
201 //Save the recursion levels
202 recursions[i] = cur->recursion;
203
204 //Release the owner
205 cur->recursion = 0;
206 cur->owner = NULL;
207 }
208 //Release the monitor
209 unlock( locks[i] );
210 }
211
212 // LIB_DEBUG_FPRINTF("Waiting now\n");
213
214 //Everything is ready to go to sleep
215 ScheduleInternal( locks, count );
216
217
218 //WE WOKE UP
219
220
221 //We are back, restore the owners and recursions
222 for( unsigned int i = 0; i < count; i++ ) {
223 monitor_desc * cur = this->monitors[i];
224
225 //Protect the monitors
226 lock( locks[i] );
227 {
228 //Release the owner
229 cur->owner = this_thrd;
230 cur->recursion = recursions[i];
231 }
232 //Release the monitor
233 unlock( locks[i] );
234 }
235}
236
237static void __signal_internal( condition * this ) {
238 if( !this->blocked.head ) return;
239
240 //Check that everything is as expected
241 assert( this->monitors );
242 assert( this->monitor_count != 0 );
243
244 LIB_DEBUG_DO(
245 if ( this->monitors != this_thread()->current_monitors ) {
246 abortf( "Signal on condition %p made outside of the correct monitor(s)", this );
247 } // if
248 );
249
250 monitor_desc * owner = this->monitors[0];
251 lock( &owner->lock );
252 {
253 thread_desc * unblock = pop_head( &this->blocked );
254 push( &owner->signal_stack, unblock );
255 }
256 unlock( &owner->lock );
257}
258
259void signal( condition * this ) {
260 __signal_internal( this );
261}
Note: See TracBrowser for help on using the repository browser.