#ifndef __monitor_cc #define __monitor_cc #include "lapi_comm.h" #include "monitor.h" char **mon_enter_req_table, **mon_enter_ack_table, **mon_exit_req_table; char **mon_exit_repl_table; volatile static int monitorEntered = 0; void *monitor_enter_req_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info); void *monitor_enter_ack_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info); void *monitor_exit_req_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info); /* void *monitor_exit_repl_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info); */ typedef struct waiting_proc { int proc; int nesting; struct waiting_proc *next; } waiting_proc; #define assert(cond) if (!(cond)) { printf("Assert failed at file %s line %d.\n", __FILE__, __LINE__); } /* Sets up the LAPI AM handlers. */ void monitor_system_init() { mon_enter_req_table = (char **)malloc(sizeof(char *) * PROCS); mon_enter_ack_table = (char **)malloc(sizeof(char *) * PROCS); mon_exit_req_table = (char **)malloc(sizeof(char *) * PROCS); mon_exit_repl_table = (char **)malloc(sizeof(char *) * PROCS); /* Perform exchanges to get the handler addresses on each proc. */ LAPI_SAFE(LAPI_Address_init(lapi_hndl, (void *)&monitor_enter_req_handler, (void **)mon_enter_req_table)); LAPI_SAFE(LAPI_Address_init(lapi_hndl, (void *)&monitor_enter_ack_handler, (void **)mon_enter_ack_table)); LAPI_SAFE(LAPI_Address_init(lapi_hndl, (void *)&monitor_exit_req_handler, (void **)mon_exit_req_table)); /* LAPI_SAFE(LAPI_Address_init(lapi_hndl, (void *)&monitor_exit_repl_handler, (void **)mon_exit_repl_table)); */ } void monitor_init(titanium_monitor_t *mon) { mon->who = -1; mon->nesting = 0; mon->sleepingProcs = NULL; mon->waitingProcs = NULL; /* no processes waiting to enter the monitor */ } void monitor_destroy(titanium_monitor_t * monitor) { waiting_proc *temp; if (monitor != 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. */ while (monitor->waitingProcs != NULL) { temp = monitor->waitingProcs; monitor->waitingProcs = monitor->waitingProcs->next; temp->next = NULL; ti_free(temp); } while (monitor->sleepingProcs != NULL) { temp = monitor->sleepingProcs; monitor->sleepingProcs = monitor->sleepingProcs->next; temp->next = NULL; ti_free(temp); } } } typedef struct { titanium_monitor_t *monitor; int req_proc; } mon_req_msg; /* Global var for monitor spin; not thread-safe. */ void monitor_enter(titanium_monitor_t * mon, int proc) { lapi_cntr_t lapi_cntr; mon_req_msg msg; monitorEntered = 0; msg.monitor = mon; msg.req_proc = MYPROC; /* printf("%d trying to get monitor %x owned by %d.\n", MYPROC, mon, proc); */ if (proc == MYPROC) { if (mon->nesting == 0) { /* printf("%d locking monitor for %d.\n", MYPROC, reqMsg->req_proc); */ mon->who = MYPROC; mon->nesting = 1; return; } else { if (mon->who == MYPROC) { /* If the requestor already holds the lock, allow it to get it again. (recursive nesting semantics) */ mon->nesting++; return; } } /* Fall through to LAPI if the lock's not free and we don't hold it. */ } lapi_cntr = 0; LAPI_Amsend(lapi_hndl, proc, mon_enter_req_table[proc], &msg, sizeof(msg), NULL, NULL, NULL, NULL, NULL); while (!monitorEntered) { } /* printf("%d entering monitor %x.\n", MYPROC, mon); */ } void *monitor_enter_ack_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info) { monitorEntered = 1; *comp_h = NULL; return NULL; } void monitor_send_go_ahead(lapi_handle_t *lapi_hndl_p, void *params) { mon_req_msg *reqMsg = (mon_req_msg *)params; /* printf("Sending go-ahead: %d->%d\n", MYPROC, reqMsg->req_proc); */ LAPI_Amsend(*lapi_hndl_p, reqMsg->req_proc, mon_enter_ack_table[reqMsg->req_proc], NULL, 0, NULL, 0, NULL, NULL, NULL); } void *monitor_enter_req_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info) { mon_req_msg *reqMsg = (mon_req_msg *)uhdr; titanium_monitor_t *mon = reqMsg->monitor; /* printf("%d recvd enter req from %d for monitor %x.\n", MYPROC, reqMsg->req_proc, reqMsg->monitor); */ if (mon->nesting == 0) { /* printf("%d locking monitor for %d.\n", MYPROC, reqMsg->req_proc); */ mon->who = reqMsg->req_proc; mon->nesting = 1; /* If the monitor is free right now, tell the requestor to go ahead. */ *comp_h = &monitor_send_go_ahead; *user_info = (void *)uhdr; return NULL; } else { if (mon->who == reqMsg->req_proc) { /* If the requestor already holds the lock, allow it to get it again. (recursive nesting semantics) */ mon->nesting++; *comp_h = &monitor_send_go_ahead; *user_info = (void *)uhdr; return NULL; } else { /* Else put the requestor on the list of waiters. */ waiting_proc *proc = (waiting_proc *)ti_malloc(sizeof(waiting_proc)); proc->proc = reqMsg->req_proc; proc->nesting = 1; proc->next = NULL; if (mon->waitingProcs == NULL) { mon->waitingProcs = proc; } else { waiting_proc *temp = mon->waitingProcs; while (temp->next != NULL) { temp = temp->next; } temp->next = proc; } *comp_h = NULL; *user_info = NULL; return NULL; } } } void monitor_exit(titanium_monitor_t * mon, int proc) { mon_req_msg msg; lapi_cntr_t lapi_cntr; if (proc == MYPROC) { assert(mon->who == MYPROC); /* Exit a monitor we don't hold? */ if (mon->nesting > 0) { mon->nesting--; } if (mon->nesting == 0) { if (mon->waitingProcs != NULL) { /* Pull the next waiter off the list. */ waiting_proc *temp = mon->waitingProcs; mon->who = temp->proc; mon->nesting = temp->nesting; mon->waitingProcs = mon->waitingProcs->next; temp->next = NULL; ti_free(temp); if (mon->nesting < 0) { /* Used for timed locks, which aren't implemented. */ printf("%d: Illegal monitor nesting level.\n", MYPROC); } else { /* Wake up the next waiter. */ assert(mon->who != MYPROC); /* Should be nested, not waiting. */ LAPI_Amsend(lapi_hndl, mon->who, mon_enter_ack_table[mon->who], NULL, 0, NULL, 0, NULL, NULL, NULL); } } else { mon->who = -1; } } return; } msg.monitor = mon; msg.req_proc = MYPROC; /* printf("%d trying to exit monitor %x.\n", MYPROC, mon); */ LAPI_Setcntr(lapi_hndl, &lapi_cntr, 0); LAPI_Amsend(lapi_hndl, proc, mon_exit_req_table[proc], &msg, sizeof(msg), NULL, 0, NULL, NULL, &lapi_cntr); LAPI_WAIT(lapi_cntr); /* printf("%d exited from monitor %x.\n", MYPROC, mon); */ } void *monitor_exit_req_handler(lapi_handle_t *lapi_hndl_p, void *uhdr, int *uhdr_len, int *msg_len, compl_hndlr_t **comp_h, void **user_info) { mon_req_msg *reqMsg = (mon_req_msg *)uhdr; int reqProc = reqMsg->req_proc; titanium_monitor_t *mon = reqMsg->monitor; if (mon->who == reqProc) { /* Should be an assert, actually. */ if (mon->nesting > 0) { mon->nesting--; } if (mon->nesting == 0) { if (mon->waitingProcs != NULL) { /* Pull the next waiter off the list. */ waiting_proc *temp = mon->waitingProcs; mon->who = temp->proc; mon->nesting = temp->nesting; mon->waitingProcs = mon->waitingProcs->next; temp->next = NULL; ti_free(temp); if (mon->nesting < 0) { /* Used for timed locks, which aren't implemented. */ printf("%d: Illegal monitor nesting level.\n", MYPROC); } else { /* Call the completion handler to send the wake-up msg to the next waiter. */ reqMsg->req_proc = mon->who; *comp_h = &monitor_send_go_ahead; *user_info = (void *)uhdr; return NULL; } } else { mon->who = -1; } } } *comp_h = NULL; *user_info = NULL; return NULL; } /* doesn't use waitTime for now */ void monitor_wait(titanium_monitor_t *monitor, jlong waitTime, int proc) { } void monitor_wait_request_handler(void *token, int obj, int reqProc) { } void monitor_wait_reply_handler(void *token, int value, int handler, int proc) { } void monitor_wait_succeeded_handler(void *token) { } void monitor_notify(titanium_monitor_t *monitor, int proc) { } void monitor_notify_request_handler(void *token, int obj, int reqProc) { } void monitor_notify_reply_handler(void *token, int value) { } void monitor_notify_all(titanium_monitor_t *monitor, int proc) { } void monitor_notify_all_request_handler(void *token, int obj, int reqProc) { } void monitor_notify_all_reply_handler(void *token, int value) { } #endif