source: src/libcfa/concurrency/monitor.c @ 5ea06d6

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newwith_gc
Last change on this file since 5ea06d6 was 5ea06d6, checked in by Thierry Delisle <tdelisle@…>, 5 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.