Commit e12d8ae0 authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

Replace service thread with ReadFileEx/WriteFileEx.

parent f89722db
...@@ -67,7 +67,6 @@ ...@@ -67,7 +67,6 @@
#include "wine/port.h" #include "wine/port.h"
#include "wine/server.h" #include "wine/server.h"
#include "winerror.h" #include "winerror.h"
#include "services.h"
#include "callback.h" #include "callback.h"
#include "file.h" #include "file.h"
...@@ -110,7 +109,7 @@ struct DosDeviceStruct { ...@@ -110,7 +109,7 @@ struct DosDeviceStruct {
unsigned obuf_size,obuf_head,obuf_tail; unsigned obuf_size,obuf_head,obuf_tail;
/* notifications */ /* notifications */
int wnd, n_read, n_write; int wnd, n_read, n_write;
HANDLE s_read, s_write; OVERLAPPED read_ov, write_ov;
/* save terminal states */ /* save terminal states */
DCB16 dcb; DCB16 dcb;
/* pointer to unknown(==undocumented) comm structure */ /* pointer to unknown(==undocumented) comm structure */
...@@ -216,12 +215,12 @@ static struct DosDeviceStruct *GetDeviceStruct(int index) ...@@ -216,12 +215,12 @@ static struct DosDeviceStruct *GetDeviceStruct(int index)
return NULL; return NULL;
} }
static int GetCommPort_fd(HANDLE handle) static int GetCommPort_ov(LPOVERLAPPED ov, int write)
{ {
int x; int x;
for (x=0; x<MAX_PORTS; x++) { for (x=0; x<MAX_PORTS; x++) {
if (COM[x].handle == handle) if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
return x; return x;
} }
...@@ -269,26 +268,32 @@ static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie) ...@@ -269,26 +268,32 @@ static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
return ioctl(fd, TIOCMSET, &mstat); return ioctl(fd, TIOCMSET, &mstat);
} }
static void CALLBACK comm_notification( ULONG_PTR private ) static void comm_waitread(struct DosDeviceStruct *ptr);
static void comm_waitwrite(struct DosDeviceStruct *ptr);
static VOID WINAPI COMM16_ReadComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
{ {
struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private; int prev ;
int prev, bleft;
DWORD len;
WORD mask = 0; WORD mask = 0;
int cid = GetCommPort_fd(ptr->handle); int cid = GetCommPort_ov(ov,0);
struct DosDeviceStruct *ptr;
if(cid<0) {
ERR("async write with bad overlapped pointer\n");
return;
}
ptr = &COM[cid];
TRACE("async notification\n");
/* read data from comm port */ /* read data from comm port */
if (status != STATUS_SUCCESS) {
ERR("async read failed\n");
COM[cid].commerror = CE_RXOVER;
return;
}
TRACE("async read completed %ld bytes\n",len);
prev = comm_inbuf(ptr); prev = comm_inbuf(ptr);
do {
bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
- ptr->ibuf_head;
if(!ReadFile(ptr->handle, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1, &len, NULL))
len = -1;
if (len > 0) {
if (!bleft) {
ptr->commerror = CE_RXOVER;
} else {
/* check for events */ /* check for events */
if ((ptr->eventmask & EV_RXFLAG) && if ((ptr->eventmask & EV_RXFLAG) &&
memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) { memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
...@@ -299,13 +304,12 @@ static void CALLBACK comm_notification( ULONG_PTR private ) ...@@ -299,13 +304,12 @@ static void CALLBACK comm_notification( ULONG_PTR private )
*(WORD*)(COM[cid].unknown) |= EV_RXCHAR; *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
mask |= CN_EVENT; mask |= CN_EVENT;
} }
/* advance buffer position */ /* advance buffer position */
ptr->ibuf_head += len; ptr->ibuf_head += len;
if (ptr->ibuf_head >= ptr->ibuf_size) if (ptr->ibuf_head >= ptr->ibuf_size)
ptr->ibuf_head = 0; ptr->ibuf_head = 0;
}
}
} while (len > 0);
/* check for notification */ /* check for notification */
if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) && if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
(comm_inbuf(ptr)>=ptr->n_read)) { (comm_inbuf(ptr)>=ptr->n_read)) {
...@@ -313,39 +317,55 @@ static void CALLBACK comm_notification( ULONG_PTR private ) ...@@ -313,39 +317,55 @@ static void CALLBACK comm_notification( ULONG_PTR private )
mask |= CN_RECEIVE; mask |= CN_RECEIVE;
} }
/* send notifications, if any */
if (ptr->wnd && mask) {
TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
}
/* on real windows, this could cause problems, since it is recursive */
/* restart the receive */
comm_waitread(ptr);
}
static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
{
int prev, bleft;
WORD mask = 0;
int cid = GetCommPort_ov(ov,1);
struct DosDeviceStruct *ptr;
if(cid<0) {
ERR("async write with bad overlapped pointer\n");
return;
}
ptr = &COM[cid];
/* read data from comm port */
if (status != STATUS_SUCCESS) {
ERR("async write failed\n");
COM[cid].commerror = CE_RXOVER;
return;
}
TRACE("async write completed %ld bytes\n",len);
/* update the buffer pointers */
prev = comm_outbuf(&COM[cid]);
ptr->obuf_tail += len;
if (ptr->obuf_tail >= ptr->obuf_size)
ptr->obuf_tail = 0;
/* write any TransmitCommChar character */ /* write any TransmitCommChar character */
if (ptr->xmit>=0) { if (ptr->xmit>=0) {
if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL)) if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL))
len = -1; len = -1;
if (len > 0) ptr->xmit = -1; if (len > 0) ptr->xmit = -1;
} }
/* write from output queue */ /* write from output queue */
prev = comm_outbuf(ptr); bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
do { ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
- ptr->obuf_tail;
if(bleft) {
if(!WriteFile(ptr->handle, ptr->outbuf + ptr->obuf_tail, bleft, &len, NULL))
len = -1;
} else
len = bleft;
if (len > 0) {
ptr->obuf_tail += len;
if (ptr->obuf_tail >= ptr->obuf_size)
ptr->obuf_tail = 0;
/* flag event */
if (ptr->obuf_tail == ptr->obuf_head) {
if (ptr->s_write) {
SERVICE_Delete( ptr->s_write );
ptr->s_write = INVALID_HANDLE_VALUE;
}
if (ptr->eventmask & EV_TXEMPTY) {
*(WORD*)(COM[cid].unknown) |= EV_TXEMPTY;
mask |= CN_EVENT;
}
}
}
} while (len > 0);
/* check for notification */ /* check for notification */
if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) && if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
(comm_outbuf(ptr)<ptr->n_write)) { (comm_outbuf(ptr)<ptr->n_write)) {
...@@ -358,30 +378,37 @@ static void CALLBACK comm_notification( ULONG_PTR private ) ...@@ -358,30 +378,37 @@ static void CALLBACK comm_notification( ULONG_PTR private )
TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask); TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask); if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
} }
/* start again if necessary */
if(bleft)
comm_waitwrite(ptr);
} }
static void comm_waitread(struct DosDeviceStruct *ptr) static void comm_waitread(struct DosDeviceStruct *ptr)
{ {
HANDLE dup=INVALID_HANDLE_VALUE; int bleft;
if (ptr->s_read != INVALID_HANDLE_VALUE) bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ?
return; (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head;
if(!DuplicateHandle(GetCurrentProcess(), ptr->handle, /* FIXME: get timeouts working properly so we can read bleft bytes */
GetCurrentProcess(), &dup, GENERIC_READ|SYNCHRONIZE, FALSE, 0 )) ReadFileEx(ptr->handle,
return; ptr->inbuf + ptr->ibuf_head,
ptr->s_read = SERVICE_AddObject( dup, comm_notification, (ULONG_PTR)ptr ); 1,
&ptr->read_ov,
COMM16_ReadComplete);
} }
static void comm_waitwrite(struct DosDeviceStruct *ptr) static void comm_waitwrite(struct DosDeviceStruct *ptr)
{ {
HANDLE dup=INVALID_HANDLE_VALUE; int bleft;
if (ptr->s_write != INVALID_HANDLE_VALUE) bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
return; ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
if(!DuplicateHandle(GetCurrentProcess(), ptr->handle, WriteFileEx(ptr->handle,
GetCurrentProcess(), &dup, GENERIC_WRITE|SYNCHRONIZE, FALSE, 0 )) ptr->outbuf + ptr->obuf_tail,
return; bleft,
ptr->s_write = SERVICE_AddObject( dup, comm_notification, (ULONG_PTR)ptr ); &ptr->write_ov,
COMM16_WriteComplete);
} }
/************************************************************************** /**************************************************************************
...@@ -590,9 +617,13 @@ INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue) ...@@ -590,9 +617,13 @@ INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
return IE_MEMORY; return IE_MEMORY;
} }
COM[port].s_read = INVALID_HANDLE_VALUE; ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
COM[port].s_write = INVALID_HANDLE_VALUE; ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
COM[port].read_ov.hEvent = CreateEventA(NULL,0,0,NULL);
COM[port].write_ov.hEvent = CreateEventA(NULL,0,0,NULL);
comm_waitread( &COM[port] ); comm_waitread( &COM[port] );
return port; return port;
} }
} }
...@@ -635,8 +666,9 @@ INT16 WINAPI CloseComm16(INT16 cid) ...@@ -635,8 +666,9 @@ INT16 WINAPI CloseComm16(INT16 cid)
/* COM port */ /* COM port */
SEGPTR_FREE(COM[cid].unknown); /* [LW] */ SEGPTR_FREE(COM[cid].unknown); /* [LW] */
SERVICE_Delete( COM[cid].s_write ); CloseHandle(COM[cid].read_ov.hEvent);
SERVICE_Delete( COM[cid].s_read ); CloseHandle(COM[cid].write_ov.hEvent);
/* free buffers */ /* free buffers */
free(ptr->outbuf); free(ptr->outbuf);
free(ptr->inbuf); free(ptr->inbuf);
...@@ -815,8 +847,15 @@ INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat) ...@@ -815,8 +847,15 @@ INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
COMM_MSRUpdate( ptr->handle, stol ); COMM_MSRUpdate( ptr->handle, stol );
if (lpStat) { if (lpStat) {
HANDLE rw_events[2];
lpStat->status = 0; lpStat->status = 0;
rw_events[0] = COM[cid].read_ov.hEvent;
rw_events[1] = COM[cid].write_ov.hEvent;
WaitForMultipleObjectsEx(2,&rw_events[0],FALSE,1,TRUE);
lpStat->cbOutQue = comm_outbuf(ptr); lpStat->cbOutQue = comm_outbuf(ptr);
lpStat->cbInQue = comm_inbuf(ptr); lpStat->cbInQue = comm_inbuf(ptr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment