// -*- Mode: CFA -*- // // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // monitor_desc.c -- // // Author : Thierry Delisle // Created On : Thd Feb 23 12:27:26 2017 // Last Modified By : Thierry Delisle // Last Modified On : -- // Update Count : 0 // #include "monitor" #include "kernel_private.h" void set_owner( monitor_desc * this, thread_desc * owner ) { //Pass the monitor appropriately this->owner = owner; //We are passing the monitor to someone else, which means recursion level is not 0 this->recursion = owner ? 1 : 0; } extern "C" { void __enter_monitor_desc(monitor_desc * this) { lock( &this->lock ); thread_desc * thrd = this_thread(); if( !this->owner ) { //No one has the monitor, just take it this->owner = thrd; this->recursion = 1; } else if( this->owner == thrd) { //We already have the monitor, just not how many times we took it assert( this->recursion > 0 ); this->recursion += 1; } else { //Some one else has the monitor, wait in line for it append( &this->entry_queue, thrd ); ScheduleInternal( &this->lock ); //ScheduleInternal will unlock spinlock, no need to unlock ourselves return; } unlock( &this->lock ); } // leave pseudo code : // decrement level // leve == 0 ? // no : done // yes : // signal stack empty ? // has leader : // bulk acquiring means we don't own the signal stack // ignore it but don't release the monitor // yes : // next in entry queue is new owner // no : // top of the signal stack is the owner // context switch to him right away // void __leave_monitor_desc(monitor_desc * this) { lock( &this->lock ); thread_desc * thrd = this_thread(); assert( thrd == this->owner ); //Leaving a recursion level, decrement the counter this->recursion -= 1; //If we haven't left the last level of recursion //it means we don't need to do anything if( this->recursion != 0) { unlock( &this->lock ); return; } //If we don't own the signal stack then just leave it to the owner if( this->stack_owner ) { assert( this->owner == this->stack_owner ); unlock( &this->lock ); return; } //We are the stack owner and have left the last recursion level. //We are in charge of passing the monitor thread_desc * new_owner = 0; //Check the signaller stack new_owner = pop( &this->signal_stack ); if( new_owner ) { //The signaller stack is not empty, //transfer control immediately set_owner( this, new_owner ); ScheduleInternal( &this->lock, new_owner ); return; } // No signaller thread // Get the next thread in the entry_queue new_owner = pop_head( &this->entry_queue ); set_owner( this, new_owner ); //We can now let other threads in safely unlock( &this->lock ); //We need to wake-up the thread ScheduleThread( new_owner ); } } void enter(monitor_desc ** monitors, int count) { for(int i = 0; i < count; i++) { __enter_monitor_desc( monitors[i] ); } } void leave(monitor_desc ** monitors, int count) { for(int i = count - 1; i >= 0; i--) { __leave_monitor_desc( monitors[i] ); } }