Hello Dmitry,
we had this problem, too. I sent a patch to wine-devel some time ago (I think
2008). It had the same flaw as yours. I sent a different patch after Alexandre
gave me the same answer. I then posted 2009 an different one. It did not make
it into wine, though. I don't know why as there was no answer. Therefor I keep
it since then in our own repository together with other serial fixes (i.e. to
make most USB serial adapters working better).
Attached the patch (rebased on 1.6). We use it rebased on then the actual wine
versions sincd 2009 and it works for us.
Am Montag, 26. August 2013, 10:56:29 schrieb Alexandre Julliard:
> Dmitry Timoshkov <dmi...@baikal.ru> writes:
> > MSDN for FlushFileBuffers says:
> > Flushes the buffers of a specified file and causes all buffered data to be
> > written to a file.
> >
> > Linux man page says:
> > tcdrain() waits until all output written to the object referred to by fd
> > has been transmitted.
>
> It's a blocking call, you can't do that on the server side.
Regards,
--
Wolfgang Walter
Studentenwerk München
Anstalt des öffentlichen Rechts
Abteilungsleiter IT
Leopoldstraße 15
80802 München
>From 2428481c2f68df5149ac3b0383579aa323246a19 Mon Sep 17 00:00:00 2001
From: Wolfgang Walter <w...@stwm.de>
Date: Tue, 20 Jan 2009 17:52:38 +0100
Subject: [PATCH] serial_flush() implements FlushFileBuffers incorrectly
FlushFileBuffers should write out any data not yet transmitted but
serial_flush() instead discards any data not yet transmitted
This is because it uses tcflush() instead of tcdrain().
Call tcdrain for serial handles directly from NtFlushBuffersFile()
(as it may block) and remove serial_flush() from server/serial.c
---
dlls/ntdll/file.c | 52 +++++++++++++++++++++++++++++++++++++++++-----------
server/serial.c | 11 +----------
2 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5147ef5..928095c 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -66,6 +66,9 @@
#ifdef HAVE_SYS_STATFS_H
# include <sys/statfs.h>
#endif
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
#ifdef HAVE_VALGRIND_MEMCHECK_H
# include <valgrind/memcheck.h>
#endif
@@ -2749,19 +2752,46 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock
{
NTSTATUS ret;
HANDLE hEvent = NULL;
-
- SERVER_START_REQ( flush_file )
- {
- req->handle = wine_server_obj_handle( hFile );
- ret = wine_server_call( req );
- hEvent = wine_server_ptr_handle( reply->event );
+ enum server_fd_type type;
+ unsigned int options;
+ int needs_close;
+ int unix_handle;
+
+ ret = server_get_unix_fd( hFile, FILE_WRITE_DATA, &unix_handle,
+ &needs_close, &type, &options );
+ if (ret) return ret;
+
+ TRACE("flush %p (type %d)\n", hFile, type);
+ if (type == FD_TYPE_SERIAL) {
+ TRACE("tcdrain %p (%d ; %d)\n", hFile, unix_handle, needs_close);
+ while (tcdrain( unix_handle ) == -1) {
+ TRACE("tcdrain %p (%d ; %d) returned -1 (%d)\n", hFile, unix_handle, needs_close, errno);
+ if (errno != EINTR) {
+ ret = FILE_GetNtStatus();
+ break;
+ }
+ }
+ TRACE("tcdrained %p (%d ; %d)\n", hFile, unix_handle, needs_close);
+ } else {
+ SERVER_START_REQ( flush_file )
+ {
+ req->handle = wine_server_obj_handle( hFile );
+ ret = wine_server_call( req );
+ hEvent = wine_server_ptr_handle( reply->event );
+ }
+ SERVER_END_REQ;
+ if (!ret && hEvent)
+ {
+ ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
+ NtClose( hEvent );
+ }
}
- SERVER_END_REQ;
- if (!ret && hEvent)
- {
- ret = NtWaitForSingleObject( hEvent, FALSE, NULL );
- NtClose( hEvent );
+
+ if (ret == STATUS_SUCCESS && IoStatusBlock) {
+ IoStatusBlock->u.Status = ret;
}
+ if (needs_close) close( unix_handle );
+ TRACE("flushed %p (type %d) ret=%08x\n", hFile, type, ret);
return ret;
}
diff --git a/server/serial.c b/server/serial.c
index 587fee1..aac20fa 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -61,7 +61,6 @@ static struct fd *serial_get_fd( struct object *obj );
static void serial_destroy(struct object *obj);
static enum server_fd_type serial_get_fd_type( struct fd *fd );
-static void serial_flush( struct fd *fd, struct event **event );
static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
struct serial
@@ -107,7 +106,7 @@ static const struct fd_ops serial_fd_ops =
{
default_fd_get_poll_events, /* get_poll_events */
default_poll_event, /* poll_event */
- serial_flush, /* flush */
+ no_flush, /* flush */
serial_get_fd_type, /* get_fd_type */
default_fd_ioctl, /* ioctl */
serial_queue_async, /* queue_async */
@@ -196,14 +195,6 @@ static void serial_queue_async( struct fd *fd, const async_data_t *data, int typ
}
}
-static void serial_flush( struct fd *fd, struct event **event )
-{
- /* MSDN says: If hFile is a handle to a communications device,
- * the function only flushes the transmit buffer.
- */
- if (tcflush( get_unix_fd(fd), TCOFLUSH ) == -1) file_set_error();
-}
-
DECL_HANDLER(get_serial_info)
{
struct serial *serial;
--
1.7.10.4