OpenBSD: Complete implementation of afs_osi_TimedSleep
[openafs.git] / src / afs / OBSD / osi_sleep.c
index 4a796d4..f06f2fb 100644 (file)
@@ -1,4 +1,38 @@
 /*
+ * $Id$
+ */
+
+/*
+copyright 2002
+the regents of the university of michigan
+all rights reserved
+
+permission is granted to use, copy, create derivative works 
+and redistribute this software and such derivative works 
+for any purpose, so long as the name of the university of 
+michigan is not used in any advertising or publicity 
+pertaining to the use or distribution of this software 
+without specific, written prior authorization.  if the 
+above copyright notice or any other identification of the 
+university of michigan is included in any copy of any 
+portion of this software, then the disclaimer below must 
+also be included.
+
+this software is provided as is, without representation 
+from the university of michigan as to its fitness for any 
+purpose, and without warranty by the university of 
+michigan of any kind, either express or implied, including 
+without limitation the implied warranties of 
+merchantability and fitness for a particular purpose. the 
+regents of the university of michigan shall not be liable 
+for any damages, including special, indirect, incidental, or 
+consequential damages, with respect to any claim arising 
+out of or in connection with the use of the software, even 
+if it has been or is hereafter advised of the possibility of 
+such damages.
+*/
+
+/*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
  *
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
-
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID("$Header$");
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
 #include "afs/afsincludes.h"   /* Afs-based standard headers */
-#include "afs/afs_stats.h"   /* afs statistics */
+#include "afs/afs_stats.h"     /* afs statistics */
 
 static char waitV;
 
 
-void afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
+time_t
+osi_Time()
 {
-    AFS_STATCNT(osi_InitWaitHandle);
-    achandle->proc = NULL;
+    struct timeval now;
+
+    getmicrotime(&now);
+    return now.tv_sec;
+}
+
+void
+afs_osi_SetTime(osi_timeval_t * atv)
+{
+    printf("afs attempted to set clock; use \"afsd -nosettime\"\n");
 }
 
 /* cancel osi_Wait */
-void afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
+void
+afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
 {
     caddr_t proc;
 
     AFS_STATCNT(osi_CancelWait);
     proc = achandle->proc;
-    if (proc == 0)
+    if (proc == NULL)
        return;
     achandle->proc = NULL;
     wakeup(&waitV);
@@ -43,45 +85,141 @@ void afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
  * Returns 0 if timeout and EINTR if signalled.
  */
-int afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
+int
+afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
 {
-    int code = 0;
-    afs_int32 endTime;
-    int timo = (ams * afs_hz) / 1000 + 1;
+    int timo, code = 0;
+    struct timeval atv, now, endTime;
 
     AFS_STATCNT(osi_Wait);
-    endTime = osi_Time() + (ams / 1000);
+
+    atv.tv_sec = ams / 1000;
+    atv.tv_usec = (ams % 1000) * 1000;
+    getmicrotime(&now);
+    timeradd(&atv, &now, &endTime);
+
     if (ahandle)
        ahandle->proc = (caddr_t) curproc;
+    AFS_ASSERT_GLOCK();
+    AFS_GUNLOCK();
+
     do {
+       timersub(&endTime, &now, &atv);
+       timo = atv.tv_sec * hz + atv.tv_usec * hz / 1000000 + 1;
        if (aintok) {
-           code = tsleep(&waitV, PCATCH | (PZERO+8), "afs_osi_Wait", timo);
-           if (code)   /* if interrupted, return EINTR */
-               code = EINTR;
+           code = tsleep(&waitV, PCATCH | PVFS, "afs_W1", timo);
+           if (code)
+               code = (code == EWOULDBLOCK) ? 0 : EINTR;
        } else
-           tsleep(&waitV, (PZERO-3), "afs_osi_Wait", timo);
+           tsleep(&waitV, PVFS, "afs_W2", timo);
 
        /* if we were cancelled, quit now */
        if (ahandle && (ahandle->proc == NULL)) {
            /* we've been signalled */
            break;
        }
-    } while (osi_Time() < endTime);
+       getmicrotime(&now);
+    } while (timercmp(&now, &endTime, <));
+
+    AFS_GLOCK();
+    return code;
+}
+
+/*
+ * All this gluck should probably also be replaced with CVs.
+ */
+typedef struct afs_event {
+    struct afs_event *next;     /* next in hash chain */
+    char *event;                /* lwp event: an address */
+    int refcount;               /* Is it in use? */
+    int seq;                    /* Sequence number: this is incremented
+                                 * by wakeup calls; wait will not return until
+                                 * it changes */
+    int cond;
+} afs_event_t;
+
+#define HASHSIZE 128
+afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
+#define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
+int afs_evhashcnt = 0;
+
+/* Get and initialize event structure corresponding to lwp event (i.e. address)
+ * */
+static afs_event_t *
+afs_getevent(char *event)
+{
+    afs_event_t *evp, *newp = 0;
+    int hashcode;
+
+    AFS_ASSERT_GLOCK();
+    hashcode = afs_evhash(event);
+    evp = afs_evhasht[hashcode];
+    while (evp) {
+        if (evp->event == event) {
+            evp->refcount++;
+            return evp;
+        }
+        if (evp->refcount == 0)
+            newp = evp;
+        evp = evp->next;
+    }
+    if (!newp) {
+        newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
+        afs_evhashcnt++;
+        newp->next = afs_evhasht[hashcode];
+        afs_evhasht[hashcode] = newp;
+        newp->seq = 0;
+    }
+    newp->event = event;
+    newp->refcount = 1;
+    return newp;
+}
+
+/* Release the specified event */
+#define relevent(evp) ((evp)->refcount--)
+
+int
+afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
+{
+    int code = 0;
+    struct afs_event *evp;
+    int seq, prio;
+    int ticks;
+
+    evp = afs_getevent(event);
+    seq = evp->seq;
+    AFS_GUNLOCK();
+    if (aintok)
+       prio = PCATCH | PPAUSE;
+    else
+       prio = PVFS;
+    ticks = (ams * afs_hz) / 1000;
+    code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
+    if (seq == evp->seq)
+       code = EINTR;
+    relevent(evp);
+    AFS_GLOCK();
     return code;
 }
 
-void afs_osi_Sleep(void *event)
+void
+afs_osi_Sleep(void *event)
 {
-    tsleep(event, PVFS, "afs", 0);
+    AFS_ASSERT_GLOCK();
+    AFS_GUNLOCK();
+    tsleep(event, PVFS, "afsslp", 0);
+    AFS_GLOCK();
 }
 
-int afs_osi_SleepSig(void *event)
+int
+afs_osi_SleepSig(void *event)
 {
-    tsleep(event, PVFS, "afs", 0);
+    afs_osi_Sleep(event);
     return 0;
 }
 
-int afs_osi_Wakeup(void *event)
+int
+afs_osi_Wakeup(void *event)
 {
     wakeup(event);
     return 1;