#ifndef __monitor_c #define __monitor_c #include #include #include #include #include #include #define MON_WAIT 0 #define MON_GRANTED 1 #if DEBUG_MONITORS #undef NDEBUG #include #define ASSERT(x) assert(x) #define CHECK_BOXPROC(box, proc) do { \ assert(box < BOXES); \ assert(proc < PROCS); \ assert(COMM_GetBoxNumberForProcNumber(proc) == box); \ } while(0) static int _debug_mon_verbose_firsttime = 1; static int _debug_mon_verbose = 0; #define DEBUG_MON(printfargs) do { \ if_pf (_debug_mon_verbose_firsttime) { \ _debug_mon_verbose = !!getenvMaster("TI_MON_VERBOSE"); \ _debug_mon_verbose_firsttime = 0; \ } \ if (_debug_mon_verbose) { \ printf printfargs; fflush(stderr); fflush(stdout); \ } } while (0) #else #define ASSERT(x) #define CHECK_BOXPROC(box, proc) #define DEBUG_MON(x) ((void)0) #endif /* macros for locking/unlocking the embedded HSL on GASNet we allow concurrent monitor operations on GASNet, so the HSL protects the individual monitor's metadata */ #ifdef COMM_GASNET #define LOCK_HSL(mon) gasnet_hsl_lock(&((mon)->hsl)) #define UNLOCK_HSL(mon) gasnet_hsl_unlock(&((mon)->hsl)) static gasnet_hsl_t monitor_creation_lock = GASNET_HSL_INITIALIZER; #else #define LOCK_HSL(mon) #define UNLOCK_HSL(mon) #endif /* ------------------------------------------------------------------------------------ */ /* Utilities */ /* ------------------------------------------------------------------------------------ */ /* Get the cdr proc trying for the monitor and set as owner - assumes HSL held */ int signal_try_queue( tic_monitor_t monitor ) { volatile proc_queue *queue = monitor->tryingProcs; /* Do we have no one trying */ if (queue == NULL) { DEBUG_MON(("SIGNAL_TRY_QUEUE: No one to signal\n")); monitor->box = (Box) -1; monitor->proc = (Process) -1; return 0; } DEBUG_MON(("SIGNAL_TRY_QUEUE: signal process %d\n", queue->proc)); monitor->tryingProcs = queue->cdr; monitor->box = queue->box; monitor->proc = queue->proc; CHECK_BOXPROC(monitor->box, monitor->proc); ti_free_handlersafe( (proc_queue*) queue ); return 1; } /* ------------------------------------------------------------------------------------ */ /* add a tryer to a monitor - assumes HSL held */ void insert_try_queue( tic_monitor_t monitor, Box box, Process proc ) { struct proc_queue *try_queue = ti_malloc_handlersafe(sizeof(struct proc_queue)); volatile proc_queue *tryingProcs = monitor->tryingProcs; CHECK_BOXPROC(box, proc); try_queue->proc = proc; try_queue->box = box; try_queue->cdr = NULL; if (tryingProcs == NULL) { monitor->tryingProcs = try_queue; } else { for ( ;tryingProcs->cdr != NULL; tryingProcs = tryingProcs->cdr) ; tryingProcs->cdr = try_queue; } } /* ------------------------------------------------------------------------------------ */ /* Move one waiting proc to trying list - assumes HSL held */ void signal_wait_queue( tic_monitor_t monitor ) { Process proc; Box box; volatile proc_queue *queue = monitor->waitingProcs; /* Do we have someone waiting */ if (queue == NULL) { DEBUG_MON(("\t\tSIGNAL_WAIT_QUEUE: no one waiting\n")); return; } /* Get cdr proc and move to the end of the trying list */ DEBUG_MON(("\t\tSINGAL_WAIT_QUEUE: Process %d signaled\n", queue->proc)); proc = queue->proc; box = queue->box; CHECK_BOXPROC(box, proc); monitor->waitingProcs = queue->cdr; /* Remove proc from the waiting list */ insert_try_queue( monitor, box, proc ); /* Add proc to the trying list */ ti_free_handlersafe( (proc_queue*) queue ); } /* ------------------------------------------------------------------------------------ */ /* remove a proc from the wait queue, if still present there - assumes HSL held returns true iff it was successfully found and removed */ int cancel_waiting_proc( tic_monitor_t monitor, Process proc ) { volatile proc_queue *current = monitor->waitingProcs; volatile proc_queue *prev = current; /* Do we have someone waiting */ if (current == NULL) { return FALSE; } if (current->proc == proc) { /* proc is first in the wait list */ monitor->waitingProcs = current->cdr; ti_free_handlersafe( (proc_queue*) current ); return TRUE; } else { /* search for proc and remove from wait list */ for (current = current->cdr; current != NULL; current = current->cdr) { if (current->proc == proc) { prev->cdr = current->cdr; ti_free_handlersafe((proc_queue*) current ); return TRUE; } prev = current; } } return FALSE; } /* ------------------------------------------------------------------------------------ */ /* Add a waiting proc - assumes HSL held */ void insert_wait_queue( tic_monitor_t monitor, Box box, Process proc ) { volatile proc_queue *waitingProcs = monitor->waitingProcs; proc_queue *wait_queue = ti_malloc_handlersafe(sizeof(proc_queue)); CHECK_BOXPROC(box, proc); wait_queue->proc = proc; wait_queue->box = box; wait_queue->cdr = NULL; if (waitingProcs == NULL) { monitor->waitingProcs = wait_queue; } else { /* Insert at the end of the list */ for ( ;waitingProcs->cdr != NULL; waitingProcs = waitingProcs->cdr) ; waitingProcs->cdr = wait_queue; } } /* ------------------------------------------------------------------------------------ */ /* Move all waiting procs to try list - assumes HSL held */ void broadcast_wait_queue( tic_monitor_t monitor ) { volatile proc_queue *trying_queue = monitor->tryingProcs; volatile proc_queue *waiting_queue = monitor->waitingProcs; if (trying_queue == NULL) { monitor->tryingProcs = waiting_queue; } else { for ( ;trying_queue->cdr != NULL; trying_queue = trying_queue->cdr) ; trying_queue->cdr = waiting_queue; } monitor->waitingProcs = NULL; } /* ------------------------------------------------------------------------------------ */ /* Get process' PMT for monitor */ struct process_monitor_table* get_pmt(jGPointer pmonitor, processInfo *pi) { struct process_monitor_table *my_pmt = pi->locked_monitors; for( ; my_pmt != NULL; my_pmt = my_pmt->cdr) if (EQUAL_GLOBAL(my_pmt->monitor, pmonitor)) break; return my_pmt; } /* ------------------------------------------------------------------------------------ */ void insert_monitor_pmt(jGPointer pmonitor, processInfo *pi) { process_monitor_table *pmt = pi->pmt_freelist; if (pmt) pi->pmt_freelist = pmt->cdr; else pmt = ti_malloc_handlersafe(sizeof(process_monitor_table)); pmt->monitor = pmonitor; pmt->nesting = 1; pmt->cdr = pi->locked_monitors; pi->locked_monitors = pmt; } /* ------------------------------------------------------------------------------------ */ void remove_monitor_from_pmt(jGPointer pmonitor, processInfo *pi) { process_monitor_table *current = pi->locked_monitors; if (current == NULL) { /* Do we own any locks? */ return; } else { /* Search for the lock */ if (EQUAL_GLOBAL(current->monitor, pmonitor)) { pi->locked_monitors = current->cdr; current->cdr = pi->pmt_freelist; pi->pmt_freelist = current; } else { process_monitor_table *prev = current; for (current = current->cdr; current != NULL; current = current->cdr) { if (EQUAL_GLOBAL(current->monitor, pmonitor)) { prev->cdr = current->cdr; current->cdr = pi->pmt_freelist; pi->pmt_freelist = current; return; } prev = current; } } } } /* ------------------------------------------------------------------------------------ */ /* Reply handlers */ /* ------------------------------------------------------------------------------------ */ /* Signal process only if granted (process knows if it is waiting) */ TI_INLINE(monitor_enter_reply) void monitor_enter_reply(tic_amtoken_t token, int running_local, int value, Process proc) { if (value != MON_WAIT) { CHECK_BOXPROC(MYBOX, proc); ASSERT( COMM_GetHisProcess(proc) != NULL ); COMM_GetHisProcess(proc)->waiting_for_monitor = value; } } TIC_AMSHORT(monitor_enter_reply, 2, 2, (token, 0, (int)a0, (Process)a1), (token, 0, (int)a0, (Process)a1)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_exit_reply) void monitor_exit_reply(tic_amtoken_t token, int running_local, Process proc, Process signal_proc, Box signal_box) { CHECK_BOXPROC(MYBOX, proc); if (signal_proc != (Process)-1) CHECK_BOXPROC(signal_box, signal_proc); ASSERT( COMM_GetHisProcess(proc) != NULL ); DEBUG_MON(("\tEXIT_REPLY_HANDLER: lock released signal process %d\n", (int)signal_proc)); COMM_GetHisProcess(proc)->signal_box = signal_box; tic_local_wmb(); COMM_GetHisProcess(proc)->signal_proc = signal_proc; } TIC_AMSHORT(monitor_exit_reply, 3, 3, (token, 0, (Process)a0, (Process)a1, (Box)a2), (token, 0, (Process)a0, (Process)a1, (Box)a2)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_wait_reply) void monitor_wait_reply(tic_amtoken_t token, int running_local, Process proc, Process signal_proc, Box signal_box) { if (signal_proc != (Process)-1) CHECK_BOXPROC(signal_box, signal_proc); DEBUG_MON(("WAIT_REPLY_HANDLER: process %d will signal process %d\n", proc, signal_proc)); COMM_GetHisProcess(proc)->signal_box = signal_box; tic_local_wmb(); COMM_GetHisProcess(proc)->signal_proc = signal_proc; } TIC_AMSHORT(monitor_wait_reply, 3, 3, (token, 0, (Process)a0, (Process)a1, (Box)a2), (token, 0, (Process)a0, (Process)a1, (Box)a2)); /* ------------------------------------------------------------------------------------ */ /* Request handlers */ /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_enter_request) void monitor_enter_request(tic_amtoken_t token, int running_local, tic_monitor_t *pmon, Box box, Process proc) { tic_monitor_t mon = *pmon; if (!mon) { /* first use - need to init monitor */ #ifdef COMM_GASNET gasnet_hsl_lock(&monitor_creation_lock); #endif mon = *pmon; if (!mon) { /* TODO: monitors are ALL leaked on conduits with internal threads - nothing we can do about it without better GC support... */ mon = (tic_monitor_t)ti_malloc_handlersafe(sizeof(struct tic_monitor_t)); monitor_init_inner(mon); tic_local_wmb(); /* PR809: order matters here */ *pmon = mon; } else ; /* no rmb needed here - handled by LOCK_HSL below */ #ifdef COMM_GASNET gasnet_hsl_unlock(&monitor_creation_lock); #endif } else ; /* no rmb needed here - handled by LOCK_HSL below */ CHECK_BOXPROC(box, proc); LOCK_HSL(mon); if ( mon->proc == (Process)-1 ) { ASSERT(mon->box == (Box)-1); mon->proc = proc; mon->box = box; UNLOCK_HSL(mon); /* Send reply, which will set waiting_for_monitor = MON_GRANTED */ if (running_local) { /* Call reply handler directly */ monitor_enter_reply(TIC_AM_DUMMYTOKEN, 1, MON_GRANTED, proc); } else { /* Send reply via AM */ tic_AMReply(2,2,(token, TIC_AMIDX(monitor_enter_reply), MON_GRANTED, proc)); } } else { /* Process must wait for the monitor */ CHECK_BOXPROC(mon->box, mon->proc); insert_try_queue(mon, box, proc); UNLOCK_HSL(mon); if (running_local) { /* Call reply handler directly */ monitor_enter_reply(TIC_AM_DUMMYTOKEN, 1, MON_WAIT, proc); } else { /* Send reply via AM */ tic_AMReply(2,2,(token, TIC_AMIDX(monitor_enter_reply), MON_WAIT, proc)); } } } TIC_AMSHORT(monitor_enter_request, 3, 4, (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR32(a0), (Box)a1, (Process)a2), (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, (Process)a3)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_signal_request) void monitor_signal_request(tic_amtoken_t token, int running_local, Process proc) { CHECK_BOXPROC(MYBOX, proc); COMM_GetHisProcess(proc)->waiting_for_monitor = MON_GRANTED; DEBUG_MON(("SIGNAL_REQUEST_HANDLER: Signal process %d has the lock\n", proc)); if (running_local) { /* Reply to the signaller */ /* do nothing */ } else { TIC_NULL_REPLY(token); } } TIC_AMSHORT(monitor_signal_request, 1, 1, (token, 0, (Process)a0), (token, 0, (Process)a0)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_exit_request) void monitor_exit_request(tic_amtoken_t token, int running_local, tic_monitor_t *pmon, Box box, Process proc) { tic_monitor_t mon = *pmon; CHECK_BOXPROC(box, proc); /* Does he own it? */ LOCK_HSL(mon); CHECK_BOXPROC(mon->box, mon->proc); if (mon->box == box && mon->proc == proc) { Process newproc; Box newbox; signal_try_queue( mon ); newproc = mon->proc; newbox = mon->box; UNLOCK_HSL(mon); if (running_local) { /* Reply with the next process to get the monitor */ monitor_exit_reply(TIC_AM_DUMMYTOKEN, 1, proc, newproc, newbox); } else { tic_AMReply(3,3,(token, TIC_AMIDX(monitor_exit_reply), proc, newproc, newbox)); } } else { /* Can't happen. */ fprintf(stderr, "Attempt to exit a monitor that process does not own\n"); abort(); } } TIC_AMSHORT(monitor_exit_request, 3, 4, (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR32(a0), (Box)a1, (Process)a2), (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, (Process)a3)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_wait_request) void monitor_wait_request(tic_amtoken_t token, int running_local, tic_monitor_t *pmon, Box box, Process proc) { tic_monitor_t mon = *pmon; DEBUG_MON(("WAIT_REQUEST_HANDLER: process %d\n", proc)); CHECK_BOXPROC(box, proc); /* Does he own it? */ LOCK_HSL(mon); if (mon->box == box && mon->proc == proc) { Process newproc; Box newbox; insert_wait_queue(mon, box, proc); signal_try_queue( mon ); newproc = mon->proc; newbox = mon->box; if (newproc != (Process)-1) CHECK_BOXPROC(newbox, newproc); UNLOCK_HSL(mon); DEBUG_MON(("WAIT_REQUEST_HANDLER: process %d signal process %d\n", proc, mon->proc)); if (running_local) { /* Reply with the next process to get the monitor */ monitor_wait_reply(TIC_AM_DUMMYTOKEN, 1, proc, newproc, newbox); } else { tic_AMReply(3,3,(token, TIC_AMIDX(monitor_wait_reply), proc, newproc, newbox)); } } else { fprintf(stderr, "Process request to wait on a monitor, which he did not own\n"); abort(); } } TIC_AMSHORT(monitor_wait_request, 3, 4, (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR32(a0), (Box)a1, (Process)a2), (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, (Process)a3)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_cancel_wait_request) void monitor_cancel_wait_request(tic_amtoken_t token,int running_local, tic_monitor_t *pmon, Box box, Process proc) { tic_monitor_t mon = *pmon; CHECK_BOXPROC(box, proc); LOCK_HSL(mon); if ( cancel_waiting_proc(mon, proc) ) insert_try_queue(mon, box, proc); if (mon->proc == (Process)-1 && mon->tryingProcs != NULL) { ASSERT(mon->box == (Box)-1); signal_try_queue( mon ); ASSERT( mon->proc == proc ); UNLOCK_HSL(mon); /* Send reply, which will set waiting_for_monitor = MON_GRANTED */ if (running_local) { /* Call reply handler directly */ monitor_enter_reply(TIC_AM_DUMMYTOKEN, 1, MON_GRANTED, proc); } else { /* Send reply via AM */ tic_AMReply(2,2,(token, TIC_AMIDX(monitor_enter_reply), MON_GRANTED, proc)); } } else { /* Process must wait for the monitor */ UNLOCK_HSL(mon); if (running_local) { /* Call reply handler directly */ monitor_enter_reply(TIC_AM_DUMMYTOKEN, 1, MON_WAIT, proc); } else { /* Send reply via AM */ tic_AMReply(2,2,(token, TIC_AMIDX(monitor_enter_reply), MON_WAIT, proc)); } } } TIC_AMSHORT(monitor_cancel_wait_request, 3, 4, (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR32(a0), (Box)a1, (Process)a2), (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, (Process)a3)); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_notify_request) void monitor_notify_request(tic_amtoken_t token, int running_local, tic_monitor_t *pmon) { tic_monitor_t mon = *pmon; int holder; LOCK_HSL(mon); signal_wait_queue(mon); holder = mon->proc; UNLOCK_HSL(mon); DEBUG_MON(("NOTIFY_REQUEST_HANDLER: process %d owns monitor\n", holder)); if (running_local) { /* Call reply handler directly */ /* do nothing */ } else { /* Send reply via AM */ TIC_NULL_REPLY(token); } } TIC_AMSHORT(monitor_notify_request, 1, 2, (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR32(a0) ), (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR64(a0, a1))); /* ------------------------------------------------------------------------------------ */ TI_INLINE(monitor_notify_all_request) void monitor_notify_all_request(tic_amtoken_t token, int running_local, tic_monitor_t *pmon, Box box, Process proc) { tic_monitor_t mon = *pmon; CHECK_BOXPROC(box, proc); LOCK_HSL(mon); broadcast_wait_queue(mon); UNLOCK_HSL(mon); if (running_local) { /* Call reply handler directly */ /* do nothing */ } else { /* Send reply via AM */ TIC_NULL_REPLY(token); } } TIC_AMSHORT(monitor_notify_all_request, 3, 4, (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR32(a0), (Box)a1, (Process)a2), (token, 0, (tic_monitor_t *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, (Process)a3)); /* ------------------------------------------------------------------------------------ */ /* External interface */ /* ------------------------------------------------------------------------------------ */ void monitor_startup() { TIC_BEGIN_FUNCTION COMM_GetMyProcess()->locked_monitors = NULL; COMM_GetMyProcess()->pmt_freelist = NULL; COMM_GetMyProcess()->signal_proc = (Process)-1; COMM_GetMyProcess()->signal_box = (Process)-1; COMM_GetMyProcess()->waiting_for_monitor = 0; } /* ------------------------------------------------------------------------------------ */ void monitor_destroy(tic_monitor_t *pmonitor) { volatile proc_queue *temp; tic_monitor_t monitor; if (pmonitor != NULL && (monitor = *pmonitor) != NULL) { /* Hopefully, the monitor will never be deallocated before */ /* replies to all processes waiting to enter the monitor are sent. */ /* However, this is done just in case this situation arises. */ LOCK_HSL(monitor); while (monitor->waitingProcs != NULL) { temp = monitor->waitingProcs; monitor->waitingProcs = monitor->waitingProcs->cdr; temp->cdr = NULL; ti_free_handlersafe((proc_queue*)temp); } while (monitor->tryingProcs != NULL) { temp = monitor->tryingProcs; monitor->tryingProcs = monitor->tryingProcs->cdr; temp->cdr = NULL; ti_free_handlersafe((proc_queue*)temp); } UNLOCK_HSL(monitor); #ifdef COMM_GASNET gasnet_hsl_destroy(&(monitor->hsl)); #endif ti_free_handlersafe(monitor); *pmonitor = NULL; } } /* ------------------------------------------------------------------------------------ */ void monitor_enter(jGPointer monitor) { TIC_BEGIN_FUNCTION struct process_monitor_table *my_pmt = get_pmt(monitor, COMM_GetMyProcess()); tic_monitor_t *pmon = (tic_monitor_t *)TO_LOCAL(monitor); Box box = TO_BOX(monitor); /* Do I already own it? */ if (my_pmt != NULL) { my_pmt->nesting++; return; } COMM_GetMyProcess()->waiting_for_monitor = MON_WAIT; if (box == MYBOX) { /* Call monitor_enter handler directly */ TIC_AM_LOCK(); monitor_enter_request(TIC_AM_DUMMYTOKEN, 1, pmon, MYBOX, MYPROC); TIC_AM_UNLOCK(); } else { /* The monitor is on another box */ tic_AMRequest(3,4,(box, TIC_AMIDX(monitor_enter_request), TIC_AMSEND_PTR(pmon), MYBOX, MYPROC)); } /* also performs rmb for critical section */ tic_poll_until( COMM_GetMyProcess()->waiting_for_monitor == MON_GRANTED ); insert_monitor_pmt(monitor, COMM_GetMyProcess()); } /* ------------------------------------------------------------------------------------ */ void monitor_exit(jGPointer monitor) { TIC_BEGIN_FUNCTION process_monitor_table* pmt = get_pmt(monitor, COMM_GetMyProcess()); if (pmt == NULL) { fprintf(stderr, "Tried to exit on a lock you didn't own.\n"); tossMonitorStateException_str("Tried to exit on a lock you didn't own.\n"); } if (pmt->nesting > 1) { pmt->nesting--; } else { /* Release monitor */ tic_monitor_t *pmon = (tic_monitor_t *)TO_LOCAL(monitor); Box box = TO_BOX(monitor); remove_monitor_from_pmt(monitor, COMM_GetMyProcess()); COMM_GetMyProcess()->signal_proc = (Process)-2; COMM_GetMyProcess()->signal_box = (Box)-2; tic_local_wmb(); /* complete writes in critical section */ DEBUG_MON(("\t\tMONITOR_EXIT: calling exit monitor request\n")); if (box == MYBOX) { TIC_AM_LOCK(); monitor_exit_request(TIC_AM_DUMMYTOKEN, 1, pmon, MYBOX, MYPROC); TIC_AM_UNLOCK(); } else { tic_AMRequest(3,4,(box, TIC_AMIDX(monitor_exit_request), TIC_AMSEND_PTR(pmon), MYBOX, MYPROC)); } DEBUG_MON(("\t\tMONITOR_EXIT: wait for next process to signal\n")); tic_poll_while(COMM_GetMyProcess()->signal_proc == (Process)-2); if (COMM_GetMyProcess()->signal_proc != (Process)-1) { /* Signal next proc */ Process signal_proc = COMM_GetMyProcess()->signal_proc; Box signal_box = COMM_GetMyProcess()->signal_box; CHECK_BOXPROC(signal_box, signal_proc); DEBUG_MON(("\t\tMONITOR_EXIT: Process %d signal process %d has the monitor\n", MYPROC, signal_proc)); if (signal_box == MYBOX) { TIC_AM_LOCK(); monitor_signal_request(TIC_AM_DUMMYTOKEN, 1, signal_proc); TIC_AM_UNLOCK(); } else { tic_AMRequest(1,1,(signal_box, TIC_AMIDX(monitor_signal_request), signal_proc)); } } else { DEBUG_MON(("\t\tMONITOR_EXIT: No next process to signal\n")); } } } /* ------------------------------------------------------------------------------------ */ void monitor_wait(jGPointer monitor, ti_time_t *tm) { TIC_BEGIN_FUNCTION Box box; int my_nesting; tic_monitor_t *pmon; process_monitor_table* pmt; DEBUG_MON(("monitor_wait: get_pmt\n")); pmt = get_pmt(monitor, COMM_GetMyProcess()); if (pmt == NULL) tossMonitorStateException_str("Tried to wait on a lock you didn't own.\n"); DEBUG_MON(("Monitor wait called for process %d nesting %d\n", MYPROC, pmt->nesting)); my_nesting = pmt->nesting; /* Save my nesting */ DEBUG_MON(("MONITOR_WAIT: Process %d has nesting %d on entry\n", MYPROC, my_nesting)); remove_monitor_from_pmt(monitor, COMM_GetMyProcess()); /* Remove monitor from list of owned monitors */ pmon = (tic_monitor_t *)TO_LOCAL(monitor); box = TO_BOX(monitor); COMM_GetMyProcess()->signal_proc = (Process)-2; /* Will poll until this becomes > -2 */ COMM_GetMyProcess()->signal_box = (Box)-2; COMM_GetMyProcess()->waiting_for_monitor = MON_WAIT; /* Will need to contend for the lock */ tic_local_wmb(); /* complete writes in critical section */ /* Release monitor and get who to signal next */ if (box == MYBOX) { TIC_AM_LOCK(); monitor_wait_request(TIC_AM_DUMMYTOKEN, 1, pmon, MYBOX, MYPROC); TIC_AM_UNLOCK(); } else { tic_AMRequest(3,4,(box, TIC_AMIDX(monitor_wait_request), TIC_AMSEND_PTR(pmon), MYBOX, MYPROC)); } DEBUG_MON(("Wait request complete process %d\n", MYPROC)); /* Poll until I know who to signal next */ tic_poll_while(COMM_GetMyProcess()->signal_proc == (Process)-2); DEBUG_MON(("Signal process %d has the lock\n", COMM_GetMyProcess()->signal_proc)); /* Signal next process if one exists */ if (COMM_GetMyProcess()->signal_proc != (Process)-1) { /* Signal next proc */ Process signal_proc = COMM_GetMyProcess()->signal_proc; Box signal_box = COMM_GetMyProcess()->signal_box; CHECK_BOXPROC(signal_box, signal_proc); if (signal_box == MYBOX) { TIC_AM_LOCK(); monitor_signal_request(TIC_AM_DUMMYTOKEN, 1, signal_proc); TIC_AM_UNLOCK(); } else { tic_AMRequest(1,1,(signal_box, TIC_AMIDX(monitor_signal_request), signal_proc)); } } DEBUG_MON(("Process %d has been signaled by %d\n", COMM_GetMyProcess()->signal_proc, MYPROC)); /* If we have a time to wait then poll while ti_millisuntil(ti_time_t tm) > 0 */ if (tm != NULL) { DEBUG_MON(("Process %d will now wait for a given amount of time\n", MYPROC)); /* Wait for a given amount of time */ while ( COMM_GetMyProcess()->waiting_for_monitor != MON_GRANTED && ti_millisuntil(tm) >= 0 ) /* can't use poll_until/while here due to timer */ tic_poll(); DEBUG_MON(("Process %d done waiting\n", MYPROC)); /* Cancel the wait for monitor, and enter monitor if not on try list */ if ( COMM_GetMyProcess()->waiting_for_monitor != MON_GRANTED ) { if (box == MYBOX) { TIC_AM_LOCK(); monitor_cancel_wait_request(TIC_AM_DUMMYTOKEN, 1, pmon, MYBOX, MYPROC); TIC_AM_UNLOCK(); } else { tic_AMRequest(3,4,(box, TIC_AMIDX(monitor_cancel_wait_request), TIC_AMSEND_PTR(pmon), MYBOX, MYPROC)); } } } /* Poll until I get the monitor back */ DEBUG_MON(("Process %d: Poll until I get the monitor back\n", MYPROC)); /* also performs rmb for critical section */ tic_poll_until( COMM_GetMyProcess()->waiting_for_monitor == MON_GRANTED ); insert_monitor_pmt(monitor, COMM_GetMyProcess()); pmt = get_pmt(monitor, COMM_GetMyProcess()); ASSERT( pmt != NULL ); pmt->nesting = my_nesting; DEBUG_MON(("MONITOR_WAIT: Process %d has nesting %d on exit\n", MYPROC, my_nesting)); } /* ------------------------------------------------------------------------------------ */ void monitor_notify(jGPointer monitor) { TIC_BEGIN_FUNCTION process_monitor_table* pmt = get_pmt(monitor, COMM_GetMyProcess()); tic_monitor_t *pmon = (tic_monitor_t *)TO_LOCAL(monitor); Box box = TO_BOX(monitor); DEBUG_MON(("\tMONITOR_NOTIFY: process %d\n", MYPROC)); if (pmt == NULL) tossMonitorStateException_str("Tried to notify a process on a lock you didn't own.\n"); if (box == MYBOX) { TIC_AM_LOCK(); monitor_notify_request(TIC_AM_DUMMYTOKEN, 1, pmon); TIC_AM_UNLOCK(); } else { tic_AMRequest(1,2,(box, TIC_AMIDX(monitor_notify_request), TIC_AMSEND_PTR(pmon))); } } /* ------------------------------------------------------------------------------------ */ void monitor_notify_all(jGPointer monitor) { TIC_BEGIN_FUNCTION process_monitor_table* pmt = get_pmt(monitor, COMM_GetMyProcess()); tic_monitor_t *pmon = (tic_monitor_t *)TO_LOCAL(monitor); Box box = TO_BOX(monitor); DEBUG_MON(("MONITOR_NOTIFY_ALL\n")); if (pmt == NULL) tossMonitorStateException_str("Tried to notify all processes on a lock you didn't own.\n"); if (box == MYBOX) { TIC_AM_LOCK(); monitor_notify_all_request(TIC_AM_DUMMYTOKEN, 1, pmon, MYBOX, MYPROC); TIC_AM_UNLOCK(); } else { tic_AMRequest(3,4,(box, TIC_AMIDX(monitor_notify_all_request), TIC_AMSEND_PTR(pmon), MYBOX, MYPROC)); } } /* ------------------------------------------------------------------------------------ */ #endif /* __monitor_c */