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

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since cd348e7 was cd348e7, checked in by Thierry Delisle <tdelisle@…>, 7 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.