#ifndef __monitor_cc #define __monitor_cc #include /* #ifdef HAVE_MONITORS */ #include #include #include #define TRUE 1 #define FALSE 0 #ifdef MEMORY_SHARED #define isMe(tid) ti_thread_equal(tid) void monitor_init(titanium_monitor_t *mon) { /* This lock controls access to the monitor structure */ ti_mutex_init(&(mon->lock)); ti_cond_init(&(mon->condvar)); mon->who = (ti_thread_t) -1; mon->nesting = 0; } void monitor_destroy(titanium_monitor_t * monitor) { ti_mutex_destroy(&(monitor->lock)); ti_cond_destroy(&(monitor->condvar)); } void monitor_enter(titanium_monitor_t *monitor) { /* Do I already own it? */ if (isMe(monitor->who)) { monitor->nesting++; } else { ti_mutex_lock(&(monitor->lock)); monitor->who = ti_thread_self(); monitor->nesting = 1; thread_cons_monitor(ti_thread_self(), monitor); } } void monitor_exit(titanium_monitor_t *monitor) { /* Do I own it? */ if (isMe(monitor->who)) { /* Yes, I own it. */ if (monitor->nesting > 1) { monitor->nesting--; } else { monitor->nesting = 0; monitor->who = (ti_thread_t) -1; thread_remove_monitor(ti_thread_self(), monitor); ti_mutex_unlock(&(monitor->lock)); } } } void monitor_wait(titanium_monitor_t *monitor, jlong millis) { int oldnesting; struct timeval now; /* struct timespec input_timeout, abs_timeout;*/ if (isMe(monitor->who)) { /* Therefore, I own the condvarlock too. */ oldnesting = monitor->nesting; monitor->nesting = 0; monitor->who = (ti_thread_t) -1; /* HACK: No timeouts right now. */ millis = 0; if (millis > 0) { /* taken from JDK implementation of timedWait */ /* input_timeout.tv_sec = millis/1000; input_timeout.tv_nsec = (millis%1000)*1000000; gettimeofday(&now, (void *)0); abs_timeout.tv_sec = now.tv_sec + input_timeout.tv_sec; abs_timeout.tv_sec += (now.tv_usec*1000 + input_timeout.tv_nsec)/(1000000000); abs_timeout.tv_nsec = (now.tv_usec*1000 + input_timeout.tv_nsec)*(1000000000); ti_cond_timedwait(&(monitor->condvar), &(monitor->lock), &abs_timeout); */ } else { thread_remove_monitor(ti_thread_self(), monitor); ti_cond_wait(&(monitor->condvar), &(monitor->lock)); } thread_cons_monitor(ti_thread_self(), monitor); monitor->who = ti_thread_self(); monitor->nesting = oldnesting; } else { printf("Tried to wait on a lock you didn't own.\n"); } } void monitor_notify(titanium_monitor_t *monitor) { if (isMe(monitor->who)) { ti_cond_signal(&(monitor->condvar)); } else { printf("Tried to notify on condition variable when you didn't own the lock.\n"); } } void monitor_notify_all(titanium_monitor_t *monitor) { if (isMe(monitor->who)) { ti_cond_broadcast(&(monitor->condvar)); } else { printf("Tried to notifyAll on condition variable when you didn't own the lock.\n"); } } #endif /* MEMORY_SHARED */ #ifdef MEMORY_DISTRIBUTED #define noHandler -1 int exitHandler = noHandler; int waitHandler = noHandler; int exitProc = -1; int waitProc = -1; int exitResponse = 0; int waitResponse = 0; int notifyResponse = 0; int notifyAllResponse = 0; int monitorEntered = 0; enum {monitorEnterRequestId, monitorEnterReplyId, monitorEnterSucceededId, monitorExitRequestId, monitorExitReplyId, monitorAckId, monitorWaitRequestId, monitorWaitReplyId, monitorWaitSucceededId, monitorNotifyRequestId, monitorNotifyReplyId, monitorNotifyAllRequestId, monitorNotifyAllReplyId}; handler_t id[13]; void set_handlers() { AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorEnterRequestId], monitor_enter_request_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorEnterReplyId], monitor_enter_reply_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorEnterSucceededId], monitor_enter_succeeded_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorExitRequestId], monitor_exit_request_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorExitReplyId], monitor_exit_reply_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorAckId], monitor_ack_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorWaitRequestId], monitor_wait_request_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorWaitReplyId], monitor_wait_reply_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorWaitSucceededId], monitor_wait_succeeded_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorNotifyRequestId], monitor_notify_request_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorNotifyReplyId], monitor_notify_reply_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorNotifyAllRequestId], monitor_notify_all_request_handler)); AM_Safe(AM_SetHandlerAny(__sc_endpoint, &id[monitorNotifyAllReplyId], monitor_notify_all_reply_handler)); } 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 */ return mon; } 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); } } } void monitor_enter(titanium_monitor_t * monitor, int proc) { AM_Safe(AM_Request2(__sc_endpoint, proc, id[monitorEnterRequestId], (int) monitor, MYPROC)); while (monitorEntered == 0) { AM_Safe(AM_Poll(__sc_bundle)); } } void monitor_exit(titanium_monitor_t * monitor, int proc) { monitorEntered = 0; AM_Safe(AM_Request2(__sc_endpoint, proc, id[monitorExitRequestId], (int) monitor, MYPROC)); while (exitResponse == 0) { AM_Safe(AM_Poll(__sc_bundle)); } if (exitHandler != noHandler) { AM_Safe(AM_Request0(__sc_endpoint, exitProc, (handler_t) exitHandler)); } exitResponse = 0; exitHandler = noHandler; exitProc = -1; } static void monitor_enter_request_handler(void *token, int obj, int reqProc) { titanium_monitor_t *mon = (titanium_monitor_t *) obj; waiting_proc *proc, *temp; int n; if (mon->nesting == 0) { mon->who = reqProc; mon->nesting = 1; AM_Safe(AM_Reply1(token, id[monitorEnterReplyId], 1)); } else { if (mon->who == reqProc) { mon->nesting++; AM_Safe(AM_Reply1(token, id[monitorEnterReplyId], 1)); } else { proc = (waiting_proc *) ti_malloc(sizeof(waiting_proc)); proc->proc = reqProc; proc->nesting = 1; proc->next = NULL; if (mon->waitingProcs == NULL) mon->waitingProcs = proc; else { temp = mon->waitingProcs; while (temp->next != NULL) temp = temp->next; temp->next = proc; } AM_Safe(AM_Reply1(token, id[monitorEnterReplyId], 0)); } } } static void monitor_enter_reply_handler(void *token, int value) { monitorEntered = value; } static void monitor_enter_succeeded_handler(void *token) { monitorEntered = 1; AM_Safe(AM_Reply0(token, id[monitorAckId])); } static void monitor_exit_request_handler(void *token, int obj, int reqProc) { titanium_monitor_t *mon = (titanium_monitor_t *) obj; waiting_proc *temp; if (mon->who == reqProc) { if (mon->nesting > 0) mon->nesting--; if (mon->nesting == 0) { if (mon->waitingProcs != NULL) { /* For now, pick first process; later, pick based on the flag (in lock) set by notify or notifyAll. */ 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) { mon->nesting = -(mon->nesting); AM_Safe(AM_Reply2(token, id[monitorExitReplyId], id[monitorWaitSucceededId], mon->who)); return; } else { AM_Safe(AM_Reply2(token, id[monitorExitReplyId], id[monitorEnterSucceededId], mon->who)); return; } } else mon->who = -1; } } AM_Safe(AM_Reply2(token, id[monitorExitReplyId], noHandler, 0)); } static void monitor_exit_reply_handler(void *token, int handler, int proc) { exitResponse = 1; exitHandler = handler; exitProc = proc; } static void monitor_ack_handler(void *token) { } /* doesn't use waitTime for now */ void monitor_wait(titanium_monitor_t *monitor, jlong waitTime, int proc) { AM_Safe(AM_Request2(__sc_endpoint, proc, id[monitorWaitRequestId], (int) monitor, MYPROC)); while (1) { if (waitResponse == 1) { break; } else if (waitResponse == -1) { printf("Tried to wait on a lock you didn't own.\n"); break; } else if (waitResponse == 0) { if (waitHandler != noHandler) { AM_Safe(AM_Request0(__sc_endpoint, waitProc, waitHandler)); waitHandler = noHandler; waitProc = -1; } AM_Safe(AM_Poll(__sc_bundle)); } } waitResponse = 0; waitHandler = noHandler; waitProc = -1; } static void monitor_wait_request_handler(void *token, int obj, int reqProc) { titanium_monitor_t *mon = (titanium_monitor_t *) obj; waiting_proc *proc, *temp; if (mon->who == reqProc) { /* Put the process that released the lock on sleeping list. */ proc = (waiting_proc *) ti_malloc(sizeof(waiting_proc)); proc->proc = mon->who; proc->nesting = -(mon->nesting); /* neg. to indicate that proc. gave up lock */ proc->next = NULL; if (mon->sleepingProcs == NULL) mon->sleepingProcs = proc; else { temp = mon->sleepingProcs; while (temp->next != NULL) temp = temp->next; temp->next = proc; } /* For now, pick the first waiting process to notify. */ if (mon->waitingProcs != NULL) { temp = mon->waitingProcs; mon->waitingProcs = mon->waitingProcs->next; temp->next = NULL; mon->who = temp->proc; mon->nesting = temp->nesting; ti_free(temp); if (mon->nesting < 0) { mon->nesting = -(mon->nesting); AM_Safe(AM_Reply3(token, id[monitorWaitReplyId], 0, (int) id[monitorWaitSucceededId], mon->who)); } else { AM_Safe(AM_Reply3(token, id[monitorWaitReplyId], 0, (int) id[monitorEnterSucceededId], mon->who)); } } else { mon->who = -1; mon->nesting = 0; AM_Safe(AM_Reply3(token, id[monitorWaitReplyId], 0, noHandler, 0)); } } else { AM_Safe(AM_Reply3(token, id[monitorWaitReplyId], -1, noHandler, 0)); } } static void monitor_wait_reply_handler(void *token, int value, int handler, int proc) { waitResponse = value; waitHandler = handler; waitProc = proc; } static void monitor_wait_succeeded_handler(void *token) { waitResponse = 1; AM_Safe(AM_Reply0(token, id[monitorAckId])); } void monitor_notify(titanium_monitor_t *monitor, int proc) { AM_Safe(AM_Request2(__sc_endpoint, proc, id[monitorNotifyRequestId], (int) monitor, MYPROC)); while (notifyResponse == 0) AM_Safe(AM_Poll(__sc_bundle)); if (notifyResponse == -1) printf("Tried to notify on lock that you didn't own.\n"); notifyResponse = 0; } static void monitor_notify_request_handler(void *token, int obj, int reqProc) { titanium_monitor_t * mon = (titanium_monitor_t *) obj; waiting_proc *proc, *temp; if (mon->who == reqProc) { /* Take the first process off the sleeping list and put it at the end of the waiting list.*/ if (mon->sleepingProcs != NULL) { proc = mon->sleepingProcs; mon->sleepingProcs = mon->sleepingProcs->next; proc->next = NULL; if (mon->waitingProcs == NULL) mon->waitingProcs = proc; else { temp = mon->waitingProcs; while (temp->next != NULL) temp = temp->next; temp->next = proc; } } AM_Safe(AM_Reply1(token, id[monitorNotifyReplyId], 1)); } else { AM_Safe(AM_Reply1(token, id[monitorNotifyReplyId], -1)); } } static void monitor_notify_reply_handler(void *token, int value) { notifyResponse = value; } void monitor_notify_all(titanium_monitor_t *monitor, int proc) { AM_Safe(AM_Request2(__sc_endpoint, proc, id[monitorNotifyAllRequestId], (int) monitor, MYPROC)); while (notifyAllResponse == 0) AM_Safe(AM_Poll(__sc_bundle)); if (notifyAllResponse == -1) printf("Tried to notifyAll on lock that you didn't own.\n"); notifyAllResponse = 0; } static void monitor_notify_all_request_handler(void *token, int obj, int reqProc) { titanium_monitor_t * mon = (titanium_monitor_t *) obj; waiting_proc *temp; if (mon->who == reqProc) { /* Take the sleeping list and append it to the waiting list. */ if (mon->waitingProcs == NULL) mon->waitingProcs = mon->sleepingProcs; else { temp = mon->waitingProcs; while (temp->next != NULL) temp = temp->next; temp->next = mon->sleepingProcs; } mon->sleepingProcs = NULL; AM_Safe(AM_Reply1(token, id[monitorNotifyAllReplyId], 1)); } else { AM_Safe(AM_Reply1(token, id[monitorNotifyAllReplyId], -1)); } } static void monitor_notify_all_reply_handler(void *token, int value) { notifyAllResponse = value; } #endif /* MEMORY_DISTRIBUTED */ #endif