rx-lwp-fdsetsize-20040708
[openafs.git] / src / lwp / iomgr.c
index f6dbc49..9c26b84 100644 (file)
@@ -7,8 +7,6 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
-#ifndef lint
-#endif
 /*******************************************************************\
 *                                                                  *
 *      Information Technology Center                               *
        IO Manager routines & server process for VICE server.
 */
 
+/* This controls the size of an fd_set; it must be defined early before
+ * the system headers define that type and the macros that operate on it.
+ * Its value should be as large as the maximum file descriptor limit we
+ * are likely to run into on any platform.  Right now, that is 65536
+ * which is the default hard fd limit on Solaris 9 */
+/* We don't do this on Windows because on that platform there is code
+ * which allocates fd_set's on the stack (IOMGR_Sleep on Win9x, and
+ * FDSetAnd on WinNT) */
+#ifndef _WIN32
+#define FD_SETSIZE 65536
+#endif
+
+#include <afsconfig.h>
 #include <afs/param.h>
+
+RCSID("$Header$");
+
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #ifdef AFS_NT40_ENV
 #include <winsock2.h>
 #include <malloc.h>
@@ -45,6 +61,17 @@ extern void lwp_abort(void);
 #ifdef AFS_SUN5_ENV
 #include <fcntl.h>
 #endif
+#ifdef AFS_DJGPP_ENV
+#include "dosdefs95.h"
+#include "netbios95.h"
+#include <sys/socket.h>
+#include <sys/farptr.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <crt0.h>
+int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY;
+#endif /* AFS_DJGPP_ENV */
+
 #if    defined(USE_PTHREADS) || defined(USE_SOLARIS_THREADS)
 
 void IOMGR_Initialize()        /* noop */
@@ -73,7 +100,11 @@ typedef unsigned char bool;
 #define TRUE   1
 
 #ifndef MIN
-#define MIN(a,b) ((a)>(b)) ? b : a
+#define MIN(a,b) (((a)>(b)) ? (b) : (a))
+#endif
+
+#ifndef NSIG
+#define NSIG 8*sizeof(sigset_t)
 #endif
 
 static int SignalSignals();
@@ -100,6 +131,11 @@ struct IoRequest {
     /* Result of select call */
     long                       result;
 
+#ifdef AFS_DJGPP_ENV
+    NCB                  *ncbp;
+    dos_ptr              dos_ncb;
+#endif /* AFS_DJGPP_ENV */
+
 };
 \f
 /********************************\
@@ -140,10 +176,20 @@ static struct timeval iomgr_badtv;
 static PROCESS iomgr_badpid;
 static void SignalIO(int fds, fd_set *rfds, fd_set *wfds, fd_set *efs,
                    int code);
+static void SignalTimeout(int code, struct timeval *timeout);
+
+#ifdef AFS_DJGPP_ENV
+/* handle Netbios NCB completion */
+static int NCB_fd;
+int anyNCBComplete = FALSE;
+int handler_seg, handler_off;  /* seg:off of NCB completion handler */
+static __dpmi_regs        callback_regs;
+static _go32_dpmi_seginfo callback_info;
+#endif /* AFS_DJGPP_ENV */
 
 /* fd_set pool managment. 
  * Use the pool instead of creating fd_set's on the stack. fd_set's can be
- * 2K in size, so making three could put 6K in the limited space of an LWP
+ * 8K in size, so making three could put 24K in the limited space of an LWP
  * stack.
  */
 struct IOMGR_fd_set {
@@ -188,7 +234,7 @@ static struct IoRequest *NewRequest()
 {
     struct IoRequest *request;
 
-    if (request=iorFreeList)
+    if ((request=iorFreeList))
        iorFreeList = (struct IoRequest *) (request->result);
     else request = (struct IoRequest *) malloc(sizeof(struct IoRequest));
 
@@ -210,7 +256,7 @@ static struct IoRequest *NewRequest()
 #else
 #define FDS_P_POS (sizeof(int)*8)
 #define INTS_PER_FDS(x) (((x)+(FDS_P_POS-1)) / FDS_P_POS)
-#define FD_N_ZERO(nfds, x) bzero((char*)(x), (INTS_PER_FDS(nfds))*sizeof(int))
+#define FD_N_ZERO(nfds, x) memset((char*)(x), 0, (INTS_PER_FDS(nfds))*sizeof(int))
 #endif
 
 #if defined(AFS_LINUX22_ENV) && (__GLIBC_MINOR__ > 0)
@@ -273,8 +319,7 @@ static void FDSetSet(int nfds, fd_set *fd_set1, fd_set *fd_set2)
     if (nfds == 0)
        return;
 
-    n = INTS_PER_FDS(nfds);
-    for (i=0; i<n; i++) {
+    for (i = 0, n = INTS_PER_FDS(nfds); i < n; i++) {
        fd_set1->FDS_BITS[i] |= fd_set2->FDS_BITS[i];
     }
 #endif
@@ -372,9 +417,6 @@ static int IOMGR(void *dummy)
        struct TM_Elem *earliest;
        struct timeval timeout, junk;
        bool woke_someone;
-#ifndef AFS_NT40_ENV
-       int fds;
-#endif
 
        FD_ZERO(&IOMGR_readfds);
        FD_ZERO(&IOMGR_writefds);
@@ -390,7 +432,9 @@ static int IOMGR(void *dummy)
            /* Note: SignalSignals() may yield! */
            if (anySigsDelivered && SignalSignals ())
                woke_someone = TRUE;
+#ifndef AFS_DJGPP_ENV
            FT_GetTimeOfDay(&junk, 0);    /* force accurate time check */
+#endif
            TM_Rescan(Requests);
            for (;;) {
                register struct IoRequest *req;
@@ -416,6 +460,12 @@ static int IOMGR(void *dummy)
                LWP_QSignal(req->pid);
                req->pid->iomgrRequest = 0;
            }
+
+#ifdef AFS_DJGPP_ENV
+            if (IOMGR_CheckNCB())    /* check for completed netbios requests */
+              woke_someone = TRUE;
+#endif /* AFS_DJGPP_ENV */
+
            if (woke_someone) LWP_DispatchProcess();
        } while (woke_someone);
 
@@ -496,6 +546,14 @@ static int IOMGR(void *dummy)
            }
 #endif /* NT40 */
 
+#ifdef AFS_DJGPP_ENV
+            /* We do this also for the DOS-box Win95 client, since
+               NCB calls don't interrupt a select, but we want to catch them
+               in a reasonable amount of time (say, half a second). */
+            iomgr_timeout.tv_sec = 0;
+            iomgr_timeout.tv_usec = IOMGR_WIN95WAITTIME;
+#endif /* DJGPP */
+
            /* Check one last time for a signal delivery.  If one comes after
               this, the signal handler will set iomgr_timeout to zero, causing
               the select to return immediately.  The timer package won't return
@@ -506,6 +564,11 @@ static int IOMGR(void *dummy)
            if (anySigsDelivered)
                continue;       /* go to the top and handle them. */
 
+#ifdef AFS_DJGPP_ENV
+            if (IOMGR_CheckNCB())    /* check for completed netbios requests */
+              LWP_DispatchProcess();
+#endif /* AFS_DJGPP_ENV */
+
 #ifdef AFS_NT40_ENV
            if (IOMGR_readfds.fd_count == 0 && IOMGR_writefds.fd_count == 0
                && IOMGR_exceptfds.fd_count == 0) {
@@ -588,10 +651,14 @@ static int IOMGR(void *dummy)
                    continue;
                }
 #endif /* AFS_NT40_ENV */
-
+#ifndef AFS_DJGPP_ENV
                FT_GetTimeOfDay(&junk, 0);
+#endif
                SignalTimeout(code, &timeout);
            }
+#ifdef AFS_DJGPP_ENV
+            IOMGR_CheckNCB();
+#endif /* AFS_DJGPP_ENV */
        }
        LWP_DispatchProcess();
     }
@@ -666,7 +733,7 @@ static void SigHandler (signo)
 
 /* Alright, this is the signal signalling routine.  It delivers LWP signals
    to LWPs waiting on Unix signals. NOW ALSO CAN YIELD!! */
-static int SignalSignals ()
+static int SignalSignals (void)
 {
     bool gotone = FALSE;
     register int i;
@@ -680,8 +747,8 @@ static int SignalSignals ()
     for (i=0; i < NSOFTSIG; i++) {
        PROCESS pid;
        if (p=sigProc[i]) /* This yields!!! */
-           LWP_CreateProcess2(p, stackSize, LWP_NORMAL_PRIORITY, sigRock[i],
-               "SignalHandler", &pid);
+           LWP_CreateProcess2(p, stackSize, LWP_NORMAL_PRIORITY, 
+                              (void *) sigRock[i], "SignalHandler", &pid);
        sigProc[i] = 0;
     }
 
@@ -747,8 +814,12 @@ int IOMGR_Initialize(void)
        IOMGR_Initialize:  so force a check for signals regardless */
     memset(allOnes, 0xff, sizeof(allOnes));
 
-    return LWP_CreateProcess(IOMGR, AFS_LWP_MINSTACKSIZE, 0, 0, "IO MANAGER",
-                            &IOMGR_Id);
+#ifdef AFS_DJGPP_ENV
+    install_ncb_handler();
+#endif /* AFS_DJGPP_ENV */
+
+    return LWP_CreateProcess(IOMGR, AFS_LWP_MINSTACKSIZE, 0, (void *) 0, 
+                            "IO MANAGER", &IOMGR_Id);
 }
 
 int IOMGR_Finalize()
@@ -963,9 +1034,7 @@ int IOMGR_Cancel(PROCESS pid)
 #ifndef AFS_NT40_ENV
 /* Cause delivery of signal signo to result in a LWP_SignalProcess of
    event. */
-IOMGR_Signal (signo, event)
-    int signo;
-    char *event;
+int IOMGR_Signal (int signo, char *event)
 {
     struct sigaction sa;
 
@@ -985,12 +1054,11 @@ IOMGR_Signal (signo, event)
 }
 
 /* Stop handling occurrences of signo. */
-IOMGR_CancelSignal (signo)
-    int signo;
+int IOMGR_CancelSignal (int signo)
 {
     if (badsig(signo) || (sigsHandled & mysigmask(signo)) == 0)
        return LWP_EBADSIG;
-    sigaction (signo, &oldActions[signo], (struct sigaction *)0);
+    sigaction (signo, &oldActions[signo], NULL);
     sigsHandled &= ~mysigmask(signo);
     return LWP_SUCCESS;
 }
@@ -998,11 +1066,171 @@ IOMGR_CancelSignal (signo)
 /* This routine calls select is a fashion that simulates the standard sleep routine */
 void IOMGR_Sleep (int seconds)
 {
+#ifndef AFS_DJGPP_ENV
     struct timeval timeout;
 
     timeout.tv_sec = seconds;
     timeout.tv_usec = 0;
     IOMGR_Select(0, 0, 0, 0, &timeout);
+#else
+    struct timeval timeout;
+    int s;
+    fd_set set, empty;
+    FD_ZERO(&empty);
+    FD_ZERO(&set);
+    s = socket(AF_INET,SOCK_STREAM,0);
+    FD_SET(s,&set);
+
+    timeout.tv_sec = seconds;
+    timeout.tv_usec = 0;
+    IOMGR_Select(1,&set,&empty,&empty,&timeout);
+    close(s);
+#endif            /* DJGPP  */
 }
 #endif /* USE_PTHREADS */
 
+
+#ifdef AFS_DJGPP_ENV
+
+/* Netbios code for djgpp port */
+
+int IOMGR_NCBSelect(NCB *ncbp, dos_ptr dos_ncb, struct timeval *timeout)
+{
+  struct IoRequest *request;
+  int result;
+  
+  if (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)
+  {
+    /* Poll */
+    if (ncbp->ncb_event != NULL)
+    {
+      /* error */
+      return -1;
+    }
+    
+    if (get_dos_member_b(NCB, dos_ncb, ncb_cmd_cplt) != 0xff)
+    {
+      return 1;
+    }
+    else {
+      return 0;
+    }
+  }
+
+  /* Construct request block & insert */
+  request = NewRequest();
+  request->ncbp = ncbp;
+  request->dos_ncb = dos_ncb;
+  
+  if (timeout == NULL)
+  {
+    request->timeout.TotalTime.tv_sec = -1;
+    request->timeout.TotalTime.tv_usec = -1;
+  }
+  else
+  {
+    request -> timeout.TotalTime = *timeout;
+    /* check for bad request */
+    if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999)
+    {
+      /* invalid arg */
+      iomgr_badtv = *timeout;
+      iomgr_badpid = LWP_ActiveProcess;
+      /* now fixup request */
+      if(request->timeout.TotalTime.tv_sec < 0)
+        request->timeout.TotalTime.tv_sec = 1;
+      request->timeout.TotalTime.tv_usec = 100000;
+    }
+  }
+
+  request->timeout.BackPointer = (char *)request;
+
+  /* Insert my PID in case of IOMGR_Cancel */
+  request -> pid = LWP_ActiveProcess;
+  LWP_ActiveProcess -> iomgrRequest = request;
+  
+#ifdef DEBUG
+  request -> timeout.Next = (struct TM_Elem *) 1;
+  request -> timeout.Prev = (struct TM_Elem *) 1;
+#endif /* DEBUG */
+  TM_Insert(Requests, &request->timeout);
+
+  if (ncbp->ncb_event != NULL)
+  {
+    /* since we were given an event, we can return immediately and just
+       signal the event once the request completes. */
+    return 0;
+  }
+  else
+  {
+    /* Wait for action */
+    
+    LWP_QWait();
+    
+    /* Update parameters & return */
+    result = request -> result;
+
+    FreeRequest(request);
+    return (result > 1 ? 1 : result);
+  }
+}
+      
+int IOMGR_CheckNCB(void)
+{
+  int woke_someone = FALSE;
+  EVENT_HANDLE ev;
+  PROCESS pid;
+  
+  anyNCBComplete = FALSE;
+  FOR_ALL_ELTS(r, Requests, {
+    register struct IoRequest *req;
+    req = (struct IoRequest *) r -> BackPointer;
+
+    if (req->dos_ncb && get_dos_member_b(NCB, req->dos_ncb, ncb_cmd_cplt) != 0xff)
+    {
+      /* this NCB has completed */
+      TM_Remove(Requests, &req->timeout);
+
+      /* copy out NCB from DOS to virtual space */
+      dosmemget(req->dos_ncb, sizeof(NCB), (char *) req->ncbp);
+
+      if (ev = req->ncbp->ncb_event)
+      {
+        thrd_SetEvent(ev);
+      }
+      else
+      {
+        woke_someone = TRUE;
+        LWP_QSignal(pid=req->pid);
+        pid->iomgrRequest = 0;
+      }
+    }
+  })
+  return woke_someone;
+}
+
+int ncb_handler(__dpmi_regs *r)
+{
+  anyNCBComplete = TRUE;  /* NCB completed */
+  /* Make sure that the IOMGR process doesn't pause on the select. */
+  iomgr_timeout.tv_sec = 0;
+  iomgr_timeout.tv_usec = 0;
+  return;
+}
+
+int install_ncb_handler(void)
+{
+  callback_info.pm_offset = (long) ncb_handler;
+  if (_go32_dpmi_allocate_real_mode_callback_retf(&callback_info,
+                                                  &callback_regs))
+ {
+      fprintf(stderr, "error, allocate_real_mode_callback_retf failed\n");
+      return -1;
+ }
+
+ handler_seg = callback_info.rm_segment;
+ handler_off = callback_info.rm_offset;
+ /*printf("NCB handler_seg=0x%x, off=0x%x\n", handler_seg, handler_off);*/
+}
+#endif /* AFS_DJGPP_ENV */