comm timeouts, msvcrt debug

Tomas Vanek Tomas.Vanek at fbl.cz
Tue Aug 10 16:24:55 CDT 2004


Short comments are included in the patches. Sorry for not beeing synced 
with CVS.
Please recheck if  wine-20040716-async-timeout-callback.patch is not a 
wrong way.

Tom
-------------- next part --------------
# 
# Fixed comm file read/write
# - behaviour of comm timeouts is much closer to Windows
# - no direct sync operation - those are always converted to async in NtRead/WriteFile
# - readinterval implemented on server using timeout, setting of c_cc[VTIME] no more needed
# - reset event in overlaped structure on starting NtRead/WriteFile
#
diff -ur wine-20040716-orig/dlls/kernel/comm.c wine-20040716/dlls/kernel/comm.c
--- wine-20040716-orig/dlls/kernel/comm.c	2004-06-16 02:12:12.000000000 +0200
+++ wine-20040716/dlls/kernel/comm.c	2004-08-09 17:11:59.000000000 +0200
@@ -1788,7 +1788,7 @@
  * Sets the timeouts used when reading and writing data to/from COMM ports.
  *
  * ReadIntervalTimeout
- *     - converted and passes to linux kernel as c_cc[VTIME]
+ *     - implemented on server using async timeout, setting of c_cc[VTIME] no more needed
  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
  *     - used in ReadFile to calculate GetOverlappedResult's timeout
  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
@@ -1828,41 +1828,6 @@
     SERVER_END_REQ;
     if (!ret) return FALSE;
 
-    /* FIXME: move this stuff to the server */
-    fd = get_comm_fd( hComm, GENERIC_READ );
-    if (fd < 0) return FALSE;
-
-    if (-1==tcgetattr(fd,&tios)) {
-        FIXME("tcgetattr on fd %d failed!\n",fd);
-        release_comm_fd( hComm, fd );
-        return FALSE;
-    }
-
-    /* VTIME is in 1/10 seconds */
-	{
-		unsigned int ux_timeout;
-
-		if(lptimeouts->ReadIntervalTimeout == 0) /* 0 means no timeout */
-		{
-			ux_timeout = 0;
-		}
-		else
-		{
-			ux_timeout = (lptimeouts->ReadIntervalTimeout+99)/100;
-			if(ux_timeout == 0)
-			{
-				ux_timeout = 1; /* must be at least some timeout */
-			}
-		}
-		tios.c_cc[VTIME] = ux_timeout;
-	}
-
-    if (-1==tcsetattr(fd,0,&tios)) {
-        FIXME("tcsetattr on fd %d failed!\n",fd);
-        release_comm_fd( hComm, fd );
-        return FALSE;
-    }
-    release_comm_fd( hComm, fd );
     return TRUE;
 }
 
diff -ur wine-20040716-orig/dlls/ntdll/file.c wine-20040716/dlls/ntdll/file.c
--- wine-20040716-orig/dlls/ntdll/file.c	2004-06-19 16:46:49.000000000 +0200
+++ wine-20040716/dlls/ntdll/file.c	2004-08-09 17:21:13.712305496 +0200
@@ -465,12 +465,20 @@
         ovp->fd_type = type;
 
         io_status->Information = 0;
+	
+	if (hEvent)
+	    NtResetEvent(hEvent, NULL);
+
         ret = register_new_async(&ovp->async);
         if (ret != STATUS_SUCCESS)
             return ret;
         if (flags & FD_FLAG_TIMEOUT)
         {
-            NtWaitForSingleObject(hEvent, TRUE, NULL);
+	    do
+	    {
+	        NtWaitForSingleObject(hEvent, TRUE, NULL);
+	    }
+	    while (io_status->u.Status == STATUS_PENDING);
             NtClose(hEvent);
         }
         else
@@ -601,6 +609,23 @@
         return STATUS_PIPE_DISCONNECTED;
     }
 
+    if (flags & FD_FLAG_TIMEOUT)
+    {
+        if (hEvent)
+        {
+            /* this shouldn't happen, but check it */
+            FIXME("NIY-hEvent\n");
+            wine_server_release_fd( hFile, unix_handle );
+            return STATUS_NOT_IMPLEMENTED;
+        }
+        io_status->u.Status = NtCreateEvent(&hEvent, SYNCHRONIZE, NULL, 0, 0);
+        if (io_status->u.Status)
+        {
+            wine_server_release_fd( hFile, unix_handle );
+            return io_status->u.Status;
+        }
+    }
+    
     if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT))
     {
         async_fileio*   ovp;
@@ -630,7 +655,10 @@
         ovp->buffer = (void*)buffer;
         ovp->fd_type = type;
 
-        io_status->Information = 0;
+	if (hEvent)
+	    NtResetEvent(hEvent, NULL);
+        
+	io_status->Information = 0;
         ret = register_new_async(&ovp->async);
         if (ret != STATUS_SUCCESS)
             return ret;
diff -ur wine-20040716-orig/server/serial.c wine-20040716/server/serial.c
--- wine-20040716-orig/server/serial.c	2004-06-16 02:12:27.000000000 +0200
+++ wine-20040716/server/serial.c	2004-08-09 18:06:22.086570024 +0200
@@ -209,8 +209,8 @@
     *flags = 0;
     if (!(serial->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
         *flags |= FD_FLAG_OVERLAPPED;
-    else if(!((serial->readinterval == MAXDWORD) &&
-              (serial->readmult == 0) && (serial->readconst == 0)) )
+    else 
+	/* always handle comm asynchronously */
         *flags |= FD_FLAG_TIMEOUT;
 
     return FD_TYPE_DEFAULT;
@@ -234,6 +234,14 @@
     set_fd_events( fd, serial_get_poll_events(fd) );
 }
 
+static void serial_readinterval_callback(void *private)
+{
+    struct async *async = (struct async *)private;
+
+    async->timeout = NULL;
+    async_notify(async, STATUS_SUCCESS);
+}
+
 static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count)
 {
     struct serial *serial = get_fd_user( fd );
@@ -247,7 +255,10 @@
     {
     case ASYNC_TYPE_READ:
         q = &serial->read_q;
-        timeout = serial->readconst + serial->readmult*count;
+	if (serial->readmult != MAXDWORD)
+	    timeout = serial->readconst + serial->readmult*count;
+	else
+	    timeout = serial->readconst;
         break;
     case ASYNC_TYPE_WAIT:
         q = &serial->wait_q;
@@ -276,18 +287,63 @@
         async->status = STATUS_PENDING;
         if(!async->q)
         {
-            async_add_timeout(async,timeout);
+	    if (type == ASYNC_TYPE_READ) {
+		if (timeout)
+		{
+		    /* read timeout on comm returns success */
+		    gettimeofday( &async->when, 0 );
+		    add_timeout( &async->when, timeout );
+		    async->timeout = add_timeout_user( &async->when, serial_readinterval_callback, async );
+		}
+	    } else 
+	    {
+		async_add_timeout(async,timeout);
+	    }
             async_insert(q, async);
         }
-
+	else if (type == ASYNC_TYPE_READ && serial->readinterval != 0) 
+	{
+	    if (serial->readmult == MAXDWORD && serial->readinterval == MAXDWORD)
+	    {
+		/* return immediately */
+		async_notify(async, STATUS_SUCCESS);
+		return;
+	    }
+	    /* if readinterval is used, it replaces timeout after reception of first char(s) */
+	    /* timeout (readconst + readmult*count) may be missed when reception goes on, fortunately buffer must get full sometime */
+            if (async->timeout)
+	    {
+	        remove_timeout_user(async->timeout);
+		async->timeout= NULL;
+	    }
+	    if (serial->readinterval != MAXDWORD)
+	    {
+	    	gettimeofday( &async->when, 0 );
+		add_timeout( &async->when, serial->readinterval );
+	    	async->timeout = add_timeout_user( &async->when, serial_readinterval_callback, async );
+	    }
+	}
+        
         /* Check if the new pending request can be served immediately */
         events = check_fd_events( fd, serial_get_poll_events( fd ) );
         if (events)
         {
             /* serial_poll_event() calls set_select_events() */
             serial_poll_event( fd, events );
+	    if ((async->status == STATUS_PENDING) && (serial->readinterval == MAXDWORD)
+	       && (serial->readmult == 0) && (serial->readconst == 0))
+	    {
+		/* return immediately */
+		async_notify(async, STATUS_SUCCESS);
+	    }
             return;
         }
+	if ((async->status == STATUS_PENDING) && (serial->readinterval == MAXDWORD)
+	  && (serial->readmult == 0) && (serial->readconst == 0))
+	{
+	    /* return immediately */
+	    async_notify(async, STATUS_SUCCESS);
+	}
     }
     else if ( async ) destroy_async ( async );
     else set_error ( STATUS_INVALID_PARAMETER );
-------------- next part --------------
# subminimal implementation of _CrtDbgReport to get MFC's TRACE() output as debug strings
diff -ur wine-20040716-orig/dlls/msvcrtd/debug.c wine-20040716/dlls/msvcrtd/debug.c
--- wine-20040716-orig/dlls/msvcrtd/debug.c	2004-06-16 02:12:15.000000000 +0200
+++ wine-20040716/dlls/msvcrtd/debug.c	2004-08-08 15:55:04.000000000 +0200
@@ -103,6 +103,14 @@
 int _CrtDbgReport(int reportType, const char *filename, int linenumber,
 		  const char *moduleName, const char *format, ...)
 {
+    va_list valist;
+    INT res;
+    CHAR buffer[1024];
+
+    va_start( valist, format );
+    res = vsprintf( buffer, format, valist );
+    va_end( valist );
+    OutputDebugStringA(buffer);
     return 0;
 }
-------------- next part --------------
# just check if argument is in range to avoid GP fault
diff -ur wine-20040716-orig/dlls/ntdll/time.c wine-20040716/dlls/ntdll/time.c
--- wine-20040716-orig/dlls/ntdll/time.c	2004-06-16 02:12:16.000000000 +0200
+++ wine-20040716/dlls/ntdll/time.c	2004-08-09 19:03:12.469113072 +0200
@@ -323,6 +323,7 @@
 void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout )
 {
     UINT remainder;
+    ULONGLONG ul;
 
     if (!timeout)  /* infinite timeout */
     {
@@ -342,9 +343,22 @@
     }
     else  /* absolute time */
     {
-        when->sec = RtlEnlargedUnsignedDivide( timeout->QuadPart - TICKS_1601_TO_1970,
+	if (timeout->QuadPart < TICKS_1601_TO_1970)
+	{
+	    WARN("Strange absolute timeout %lld (before year 1970), set to 0\n", timeout->QuadPart);
+	    when->sec = when->usec = 0;
+	}
+	else if (timeout->QuadPart > TICKS_1601_TO_1970 + (ULONGLONG)TICKSPERSEC * MAXDWORD)
+	{
+	    WARN("Strange absolute timeout %lld (so far in the future as DWORD overflows), set to MAXDWORD\n", timeout->QuadPart);
+	    when->sec = MAXDWORD, when->usec = 999999;
+	}
+	else
+	{
+            when->sec = RtlEnlargedUnsignedDivide( timeout->QuadPart - TICKS_1601_TO_1970,
                                                   TICKSPERSEC, &remainder );
-        when->usec = remainder / 10;
+	    when->usec = remainder / 10;
+	}
     }
 }
 
-------------- next part --------------
# I'm not sure about this.
# Async shoud not be destroyed to save status for next queue_async() call.
# Otherwise at least serial_queue_async() override STATUS_TIMEOUT by STATUS_INVALID_PARAMETER.
# Is that correct?
diff -ur -U 7 wine-20040716-orig/server/async.c wine-20040716/server/async.c
--- wine-20040716-orig/server/async.c	2003-04-09 00:45:37.000000000 +0200
+++ wine-20040716/server/async.c	2004-08-09 19:23:13.247567000 +0200
@@ -111,15 +111,14 @@
 static void async_callback(void *private)
 {
     struct async *async = (struct async *)private;
 
     /* fprintf(stderr,"%p timeout out\n",async->overlapped); */
     async->timeout = NULL;
     async_notify(async, STATUS_TIMEOUT);
-    destroy_async(async);
 }
 
 struct async *create_async(struct object *obj, struct thread *thread,
                            void *overlapped)
 {
     struct async *async = (struct async *) malloc(sizeof(struct async));
     if(!async)


More information about the wine-patches mailing list