Fix for bug 69285 "Mozilla is unresponsive after sleep", patch=sfraser, gordon, r=wtc.
authorgordon%netscape.com
Fri, 08 Jun 2001 23:19:29 +0000
changeset 1935 a245729a5b7879d81d0b1ae6f644fb72ccb90714
parent 1934 e2b97fb2b8c059dec0c4293f8e34328d78228a96
child 1936 ccaea6e28532f5535299bee5751b0729cf1ac44b
push idunknown
push userunknown
push dateunknown
reviewerswtc
bugs69285
Fix for bug 69285 "Mozilla is unresponsive after sleep", patch=sfraser, gordon, r=wtc.
pr/src/io/prpolevt.c
pr/src/md/mac/macsockotpt.c
--- a/pr/src/io/prpolevt.c
+++ b/pr/src/io/prpolevt.c
@@ -127,16 +127,203 @@ PR_IMPLEMENT(PRStatus) PR_WaitForPollabl
     status = sys$clref(-PR_FileDesc2NativeHandle(event));
     if (!$VMS_STATUS_SUCCESS(status)) {
         PR_SetError(PR_INVALID_ARGUMENT_ERROR, status);
         return PR_FAILURE;
     }
     return PR_SUCCESS;
 }
 
+#elif defined (XP_MAC)
+
+#include "primpl.h"
+
+/*
+ * On Mac, local sockets cannot be used, because the networking stack
+ * closes them when the machine goes to sleep. Instead, we'll use a simple
+ * flag.
+ */
+
+
+/*
+ * PRFilePrivate structure for the NSPR pollable events layer
+ */
+typedef struct PRPollableDesc {
+    PRBool      gotEvent;
+    PRThread    *pollingThread;
+} PRPollableDesc;
+
+static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd);
+
+static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags);
+
+static PRIOMethods _pr_mac_polevt_methods = {
+    PR_DESC_LAYERED,
+    _pr_MacPolEvtClose,
+    (PRReadFN)_PR_InvalidInt,
+    (PRWriteFN)_PR_InvalidInt,
+    (PRAvailableFN)_PR_InvalidInt,
+    (PRAvailable64FN)_PR_InvalidInt64,
+    (PRFsyncFN)_PR_InvalidStatus,
+    (PRSeekFN)_PR_InvalidInt,
+    (PRSeek64FN)_PR_InvalidInt64,
+    (PRFileInfoFN)_PR_InvalidStatus,
+    (PRFileInfo64FN)_PR_InvalidStatus,
+    (PRWritevFN)_PR_InvalidInt,        
+    (PRConnectFN)_PR_InvalidStatus,        
+    (PRAcceptFN)_PR_InvalidDesc,        
+    (PRBindFN)_PR_InvalidStatus,        
+    (PRListenFN)_PR_InvalidStatus,        
+    (PRShutdownFN)_PR_InvalidStatus,    
+    (PRRecvFN)_PR_InvalidInt,        
+    (PRSendFN)_PR_InvalidInt,        
+    (PRRecvfromFN)_PR_InvalidInt,    
+    (PRSendtoFN)_PR_InvalidInt,        
+    _pr_MacPolEvtPoll,
+    (PRAcceptreadFN)_PR_InvalidInt,   
+    (PRTransmitfileFN)_PR_InvalidInt, 
+    (PRGetsocknameFN)_PR_InvalidStatus,    
+    (PRGetpeernameFN)_PR_InvalidStatus,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRReservedFN)_PR_InvalidInt,    
+    (PRGetsocketoptionFN)_PR_InvalidStatus,
+    (PRSetsocketoptionFN)_PR_InvalidStatus,
+    (PRSendfileFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt, 
+    (PRReservedFN)_PR_InvalidInt
+};
+
+static PRDescIdentity _pr_mac_polevt_id;
+static PRCallOnceType _pr_mac_polevt_once_control;
+static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void);
+
+static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll(
+    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
+{
+    PRPollableDesc   *pollDesc = (PRPollableDesc *)fd->secret;
+    PR_ASSERT(pollDesc);
+
+    // set the current thread so that we can wake up the poll thread
+    pollDesc->pollingThread = PR_GetCurrentThread();
+
+    if ((in_flags & PR_POLL_READ) && pollDesc->gotEvent)
+        *out_flags = PR_POLL_READ;
+    else
+        *out_flags = 0;
+    return pollDesc->gotEvent ? 1 : 0;
+}
+
+static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void)
+{
+    _pr_mac_polevt_id = PR_GetUniqueIdentity("NSPR pollable events");
+    if (PR_INVALID_IO_LAYER == _pr_mac_polevt_id) {
+        return PR_FAILURE;
+    }
+    return PR_SUCCESS;
+}
+
+static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd)
+{
+    PRPollableDesc   *pollDesc = (PRPollableDesc *)fd->secret;
+    PR_ASSERT(NULL == fd->higher && NULL == fd->lower);
+    PR_ASSERT(pollDesc);
+    PR_DELETE(pollDesc);
+    fd->dtor(fd);
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void)
+{
+    PRFileDesc      *event;
+    PRPollableDesc   *pollDesc;
+    
+    if (PR_CallOnce(&_pr_mac_polevt_once_control, _pr_MacPolEvtInit) == PR_FAILURE) {
+        return NULL;
+    }
+
+    event = PR_CreateIOLayerStub(_pr_mac_polevt_id, &_pr_mac_polevt_methods);
+    if (NULL == event) {
+        return NULL;
+    } 
+
+    /*
+    ** Allocate an event flag and clear it.
+    */
+    pollDesc = PR_NEW(PRPollableDesc);
+    if (!pollDesc) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        goto errorExit;
+    }
+
+    pollDesc->gotEvent = PR_FALSE;
+    pollDesc->pollingThread = NULL;
+    
+    event->secret = (PRFilePrivate*)pollDesc;
+    return event;
+
+errorExit:
+
+    if (event) {
+        PR_DELETE(event->secret);
+        event->dtor(event);
+    }
+    return NULL;
+}
+
+PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event)
+{
+    return PR_Close(event);
+}
+
+/* from macsockotpt.c. I wish there was a cleaner way */
+extern void WakeUpNotifiedThread(PRThread *thread, OTResult result);
+
+PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event)
+{
+    PRPollableDesc   *pollDesc = (PRPollableDesc *)event->secret;
+    PR_ASSERT(pollDesc);
+    PR_ASSERT(pollDesc->pollingThread->state != _PR_DEAD_STATE);
+    
+    if (pollDesc->pollingThread->state == _PR_DEAD_STATE)
+      return PR_FAILURE;
+
+    pollDesc->gotEvent = PR_TRUE;
+    
+    if (pollDesc->pollingThread)
+        WakeUpNotifiedThread(pollDesc->pollingThread, noErr);
+        
+    return PR_SUCCESS;
+}
+
+PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event)
+{
+    PRPollableDesc   *pollDesc = (PRPollableDesc *)event->secret;
+    PRStatus status;    
+    PR_ASSERT(pollDesc);
+    
+    /*
+      FIXME: Danger Will Robinson!
+      
+      The current implementation of PR_WaitForPollableEvent is somewhat
+      bogus; it makes the assumption that, in Mozilla, this will only
+      ever be called when PR_Poll has returned, telling us that an
+      event has been set.
+    */
+    
+    PR_ASSERT(pollDesc->gotEvent);
+    
+    status = (pollDesc->gotEvent) ? PR_SUCCESS : PR_FAILURE;
+    pollDesc->gotEvent = PR_FALSE;
+    return status;    
+}
+
 #else /* VMS */
 
 /*
  * These internal functions are declared in primpl.h,
  * but we can't include primpl.h because the definition
  * of struct PRFilePrivate in this file (for the pollable
  * event layer) will conflict with the definition of
  * struct PRFilePrivate in primpl.h (for the NSPR layer).
--- a/pr/src/md/mac/macsockotpt.c
+++ b/pr/src/md/mac/macsockotpt.c
@@ -69,16 +69,19 @@ static struct {
 
 
 static pascal void  DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
 static pascal void  NotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
 static pascal void  RawEndpointNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
 
 static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PRBool *exceptReady);
 
+void
+WakeUpNotifiedThread(PRThread *thread, OTResult result);
+
 extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
 extern void DoneWaitingOnThisThread(PRThread *thread);
 
 #if TARGET_CARBON
 OTClientContextPtr  clientContext = NULL;
 
 #define INIT_OPEN_TRANSPORT()	InitOpenTransportInContext(kInitOTForExtensionMask, &clientContext)
 #define OT_OPEN_INTERNET_SERVICES(config, flags, err)	OTOpenInternetServicesInContext(config, flags, err, clientContext)
@@ -278,17 +281,17 @@ static void macsock_map_error(OSStatus e
 static void PrepareForAsyncCompletion(PRThread * thread, PRInt32 osfd)
 {
     thread->io_pending       = PR_TRUE;
     thread->io_fd            = osfd;
     thread->md.osErrCode     = noErr;
 }
 
 
-static void
+void
 WakeUpNotifiedThread(PRThread *thread, OTResult result)
 {
     _PRCPU *      cpu      = _PR_MD_CURRENT_CPU(); 
 
 	if (thread) {
 		thread->md.osErrCode = result;
 		if (_PR_MD_GET_INTSOFF()) {
 			cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
@@ -1734,47 +1737,49 @@ static PRInt32 CheckPollDescs(PRPollDesc
             }
             else
             {
                 PRFileDesc *bottomFD;
                 PRBool readReady, writeReady, exceptReady;
 
                 pd->out_flags = 0;  /* pre-condition */
                 bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
-                PR_ASSERT(NULL != bottomFD);
-                	
-            if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
-            {
-                    if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
+                /* bottomFD can be NULL for pollable sockets */
+                if (bottomFD)
+                {
+                    if (_PR_FILEDESC_OPEN == bottomFD->secret->state)
                     {
-                        if (readReady)
-                        {
-                            if (in_flags_read & PR_POLL_READ)
-                                pd->out_flags |= PR_POLL_READ;
-                            if (in_flags_write & PR_POLL_READ)
-                                pd->out_flags |= PR_POLL_WRITE;
-                        }
-                        if (writeReady)
+                        if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
                         {
-                            if (in_flags_read & PR_POLL_WRITE)
-                                pd->out_flags |= PR_POLL_READ;
-                            if (in_flags_write & PR_POLL_WRITE)
-                                pd->out_flags |= PR_POLL_WRITE;
+                            if (readReady)
+                            {
+                                if (in_flags_read & PR_POLL_READ)
+                                    pd->out_flags |= PR_POLL_READ;
+                                if (in_flags_write & PR_POLL_READ)
+                                    pd->out_flags |= PR_POLL_WRITE;
+                            }
+                            if (writeReady)
+                            {
+                                if (in_flags_read & PR_POLL_WRITE)
+                                    pd->out_flags |= PR_POLL_READ;
+                                if (in_flags_write & PR_POLL_WRITE)
+                                    pd->out_flags |= PR_POLL_WRITE;
+                            }
+                            if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT))
+                            {
+                                pd->out_flags |= PR_POLL_EXCEPT;
+                            }
+                            if (0 != pd->out_flags) ready++;
                         }
-                        if (exceptReady && (pd->in_flags & PR_POLL_EXCEPT))
-                        {
-                            pd->out_flags |= PR_POLL_EXCEPT;
-                        }
-                        if (0 != pd->out_flags) ready++;
                     }
-                }
-            else    /* bad state */
-                {
-                    ready += 1;  /* this will cause an abrupt return */
-                    pd->out_flags = PR_POLL_NVAL;  /* bogii */
+                    else    /* bad state */
+                    {
+                        ready += 1;  /* this will cause an abrupt return */
+                        pd->out_flags = PR_POLL_NVAL;  /* bogii */
+                    }
                 }
             }
         }
 
     return ready;
 }
 
 // set or clear md.poll.thread on the poll descriptors
@@ -1783,17 +1788,16 @@ static void SetDescPollThread(PRPollDesc
     PRInt32     ready = 0;
     PRPollDesc *pd, *epd;
 
     for (pd = pds, epd = pd + npds; pd < epd; pd++)
     {   
         if (pd->fd)
         { 
             PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
-            PR_ASSERT(NULL != bottomFD);
             if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
             {
                 bottomFD->secret->md.poll.thread = thread;
             }
         }        
     }
 }