source: src/libcfa/concurrency/monitor.c@ 278516c

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 278516c was cd348e7, checked in by Thierry Delisle <tdelisle@…>, 8 years ago

Fixed mutual exclusion on monitors

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