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