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
RevLine 
[f07e037]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//
[84c52a8]8// monitor_desc.c --
[f07e037]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"
[5ea06d6]20#include "libhdr.h"
[f07e037]21
[690f13c]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
[cb0e6de]30extern "C" {
[5ea06d6]31        void __enter_monitor_desc(monitor_desc * this, monitor_desc * leader) {
[cb0e6de]32                lock( &this->lock );
33                thread_desc * thrd = this_thread();
[f07e037]34
[cd348e7]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);
[5ea06d6]39
[cb0e6de]40                if( !this->owner ) {
41                        //No one has the monitor, just take it
[cd348e7]42                        set_owner( this, thrd );
[cb0e6de]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 );
[cc7f4b1]53
[cb0e6de]54                        //ScheduleInternal will unlock spinlock, no need to unlock ourselves
55                        return; 
56                }
[f07e037]57
[cb0e6de]58                unlock( &this->lock );
[5ea06d6]59                return;
[cb0e6de]60        }
[f07e037]61
[690f13c]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        //
[5ea06d6]77        void __leave_monitor_desc(monitor_desc * this, monitor_desc * leader) {
[cb0e6de]78                lock( &this->lock );
[f07e037]79
[cd348e7]80                LIB_DEBUG_PRINT_SAFE("Leaving %p (o: %p, r: %i)\n", this, this->owner, this->recursion);
81
[cb0e6de]82                thread_desc * thrd = this_thread();
[cd348e7]83                assertf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i)", this->owner, thrd, this->recursion );
[cc7f4b1]84
[cb0e6de]85                //Leaving a recursion level, decrement the counter
86                this->recursion -= 1;
[f07e037]87
[690f13c]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) {
[cd348e7]91                        // this->stack_owner = leader;
[690f13c]92                        unlock( &this->lock );
93                        return;
94                }
95                       
[cd348e7]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                // }
[690f13c]102
103                //We are the stack owner and have left the last recursion level.
104                //We are in charge of passing the monitor
[cb0e6de]105                thread_desc * new_owner = 0;
[cc7f4b1]106
[690f13c]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 );
[cd348e7]113                        // this->stack_owner = leader;
[690f13c]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 );
[f07e037]122
[cd348e7]123                // //Update the stack owner
124                // this->stack_owner = leader;
[5ea06d6]125
[690f13c]126                //We can now let other threads in safely
[cb0e6de]127                unlock( &this->lock );
[51f3798]128
[690f13c]129                //We need to wake-up the thread
130                ScheduleThread( new_owner );
[cc7f4b1]131        }
[2781e65]132}
133
[5ea06d6]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] );
[2781e65]138        }
139}
140
[5ea06d6]141static inline void leave(monitor_desc ** monitors, int count) {
142        __leave_monitor_desc( monitors[0], NULL );
[cd348e7]143        for(int i = count - 1; i >= 1; i--) {
[5ea06d6]144                __leave_monitor_desc( monitors[i], monitors[0] );
[2781e65]145        }
[5ea06d6]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 ) {
[cd348e7]171        assertf(false, "NO SUPPORTED");
[5ea06d6]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 ) {
[cd348e7]242        assertf(false, "NO SUPPORTED");
[5ea06d6]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 );
[f07e037]266}
Note: See TracBrowser for help on using the repository browser.