From patchwork Mon Dec 12 22:43:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 705212 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tczcc49sHz9s3v for ; Tue, 13 Dec 2016 10:31:28 +1100 (AEDT) Received: from localhost ([::1]:34161 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cGa46-00028M-FM for incoming@patchwork.ozlabs.org; Mon, 12 Dec 2016 18:31:26 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43909) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cGZMT-0005Nl-1K for qemu-devel@nongnu.org; Mon, 12 Dec 2016 17:46:23 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cGZMR-0004bC-0C for qemu-devel@nongnu.org; Mon, 12 Dec 2016 17:46:21 -0500 Received: from mx1.redhat.com ([209.132.183.28]:36566) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cGZMQ-0004ar-NL for qemu-devel@nongnu.org; Mon, 12 Dec 2016 17:46:18 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D47894DD7C for ; Mon, 12 Dec 2016 22:46:17 +0000 (UTC) Received: from localhost (ovpn-116-54.ams2.redhat.com [10.36.116.54]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uBCMkFjX016727; Mon, 12 Dec 2016 17:46:16 -0500 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Tue, 13 Dec 2016 01:43:14 +0300 Message-Id: <20161212224325.20790-44-marcandre.lureau@redhat.com> In-Reply-To: <20161212224325.20790-1-marcandre.lureau@redhat.com> References: <20161212224325.20790-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Mon, 12 Dec 2016 22:46:17 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 43/54] char: move win chardev base class in its own file X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pbonzini@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- chardev/char-win.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++ chardev/char.c | 256 +------------------------------------------------- chardev/Makefile.objs | 1 + chardev/char-win.h | 30 ++++++ 4 files changed, 279 insertions(+), 253 deletions(-) create mode 100644 chardev/char-win.c create mode 100644 chardev/char-win.h diff --git a/chardev/char-win.c b/chardev/char-win.c new file mode 100644 index 0000000000..ad69c384fe --- /dev/null +++ b/chardev/char-win.c @@ -0,0 +1,245 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qapi/error.h" +#include "char-win.h" + +static void win_chr_readfile(Chardev *chr) +{ + WinChardev *s = WIN_CHARDEV(chr); + + int ret, err; + uint8_t buf[CHR_READ_BUF_LEN]; + DWORD size; + + ZeroMemory(&s->orecv, sizeof(s->orecv)); + s->orecv.hEvent = s->hrecv; + ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); + } + } + + if (size > 0) { + qemu_chr_be_write(chr, buf, size); + } +} + +static void win_chr_read(Chardev *chr) +{ + WinChardev *s = WIN_CHARDEV(chr); + + if (s->len > s->max_size) { + s->len = s->max_size; + } + if (s->len == 0) { + return; + } + + win_chr_readfile(chr); +} + +static int win_chr_read_poll(Chardev *chr) +{ + WinChardev *s = WIN_CHARDEV(chr); + + s->max_size = qemu_chr_be_can_write(chr); + return s->max_size; +} + +static int win_chr_poll(void *opaque) +{ + Chardev *chr = CHARDEV(opaque); + WinChardev *s = WIN_CHARDEV(opaque); + COMSTAT status; + DWORD comerr; + + ClearCommError(s->hcom, &comerr, &status); + if (status.cbInQue > 0) { + s->len = status.cbInQue; + win_chr_read_poll(chr); + win_chr_read(chr); + return 1; + } + return 0; +} + +int win_chr_init(Chardev *chr, const char *filename, Error **errp) +{ + WinChardev *s = WIN_CHARDEV(chr); + COMMCONFIG comcfg; + COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; + COMSTAT comstat; + DWORD size; + DWORD err; + + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hsend) { + error_setg(errp, "Failed CreateEvent"); + goto fail; + } + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hrecv) { + error_setg(errp, "Failed CreateEvent"); + goto fail; + } + + s->hcom = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (s->hcom == INVALID_HANDLE_VALUE) { + error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); + s->hcom = NULL; + goto fail; + } + + if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { + error_setg(errp, "Failed SetupComm"); + goto fail; + } + + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); + size = sizeof(COMMCONFIG); + GetDefaultCommConfig(filename, &comcfg, &size); + comcfg.dcb.DCBlength = sizeof(DCB); + CommConfigDialog(filename, NULL, &comcfg); + + if (!SetCommState(s->hcom, &comcfg.dcb)) { + error_setg(errp, "Failed SetCommState"); + goto fail; + } + + if (!SetCommMask(s->hcom, EV_ERR)) { + error_setg(errp, "Failed SetCommMask"); + goto fail; + } + + cto.ReadIntervalTimeout = MAXDWORD; + if (!SetCommTimeouts(s->hcom, &cto)) { + error_setg(errp, "Failed SetCommTimeouts"); + goto fail; + } + + if (!ClearCommError(s->hcom, &err, &comstat)) { + error_setg(errp, "Failed ClearCommError"); + goto fail; + } + qemu_add_polling_cb(win_chr_poll, chr); + return 0; + + fail: + return -1; +} + +int win_chr_pipe_poll(void *opaque) +{ + Chardev *chr = CHARDEV(opaque); + WinChardev *s = WIN_CHARDEV(opaque); + DWORD size; + + PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); + if (size > 0) { + s->len = size; + win_chr_read_poll(chr); + win_chr_read(chr); + return 1; + } + return 0; +} + +/* Called with chr_write_lock held. */ +static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1) +{ + WinChardev *s = WIN_CHARDEV(chr); + DWORD len, ret, size, err; + + len = len1; + ZeroMemory(&s->osend, sizeof(s->osend)); + s->osend.hEvent = s->hsend; + while (len > 0) { + if (s->hsend) { + ret = WriteFile(s->hcom, buf, len, &size, &s->osend); + } else { + ret = WriteFile(s->hcom, buf, len, &size, NULL); + } + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); + if (ret) { + buf += size; + len -= size; + } else { + break; + } + } else { + break; + } + } else { + buf += size; + len -= size; + } + } + return len1 - len; +} + +static void char_win_finalize(Object *obj) +{ + Chardev *chr = CHARDEV(obj); + WinChardev *s = WIN_CHARDEV(chr); + + if (s->skip_free) { + return; + } + + if (s->hsend) { + CloseHandle(s->hsend); + s->hsend = NULL; + } + if (s->hrecv) { + CloseHandle(s->hrecv); + s->hrecv = NULL; + } + if (s->hcom) { + CloseHandle(s->hcom); + s->hcom = NULL; + } + if (s->fpipe) { + qemu_del_polling_cb(win_chr_pipe_poll, chr); + } else { + qemu_del_polling_cb(win_chr_poll, chr); + } + + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); +} + +void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out) +{ + WinChardev *s = WIN_CHARDEV(chr); + + s->skip_free = true; + s->hcom = fd_out; +} + +static void char_win_class_init(ObjectClass *oc, void *data) +{ + ChardevClass *cc = CHARDEV_CLASS(oc); + + cc->chr_write = win_chr_write; +} + +static const TypeInfo char_win_type_info = { + .name = TYPE_CHARDEV_WIN, + .parent = TYPE_CHARDEV, + .instance_size = sizeof(WinChardev), + .instance_finalize = char_win_finalize, + .class_init = char_win_class_init, + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&char_win_type_info); +} + +type_init(register_types); diff --git a/chardev/char.c b/chardev/char.c index 17d47395a7..3b7140482c 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -88,6 +88,9 @@ #include "char-mux.h" #include "char-fd.h" #include "char-io.h" +#ifdef _WIN32 +#include "char-win.h" +#endif #define TCP_MAX_FDS 16 @@ -1469,23 +1472,6 @@ static void qemu_chr_open_pp_fd(Chardev *chr, #define HAVE_CHARDEV_SERIAL 1 -typedef struct { - Chardev parent; - int max_size; - HANDLE hcom, hrecv, hsend; - OVERLAPPED orecv; - BOOL fpipe; - DWORD len; - - /* Protected by the Chardev chr_write_lock. */ - OVERLAPPED osend; - /* FIXME: file/console do not finalize */ - BOOL skip_free; -} WinChardev; - -#define TYPE_CHARDEV_WIN "chardev-win" -#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN) - typedef struct { Chardev parent; HANDLE hStdIn; @@ -1499,220 +1485,9 @@ typedef struct { #define WIN_STDIO_CHARDEV(obj) \ OBJECT_CHECK(WinStdioChardev, (obj), TYPE_CHARDEV_WIN_STDIO) -#define NSENDBUF 2048 -#define NRECVBUF 2048 #define MAXCONNECT 1 #define NTIMEOUT 5000 -static int win_chr_poll(void *opaque); -static int win_chr_pipe_poll(void *opaque); - -static void char_win_finalize(Object *obj) -{ - Chardev *chr = CHARDEV(obj); - WinChardev *s = WIN_CHARDEV(chr); - - if (s->skip_free) { - return; - } - - if (s->hsend) { - CloseHandle(s->hsend); - s->hsend = NULL; - } - if (s->hrecv) { - CloseHandle(s->hrecv); - s->hrecv = NULL; - } - if (s->hcom) { - CloseHandle(s->hcom); - s->hcom = NULL; - } - if (s->fpipe) - qemu_del_polling_cb(win_chr_pipe_poll, chr); - else - qemu_del_polling_cb(win_chr_poll, chr); - - qemu_chr_be_event(chr, CHR_EVENT_CLOSED); -} - -static int win_chr_init(Chardev *chr, const char *filename, Error **errp) -{ - WinChardev *s = WIN_CHARDEV(chr); - COMMCONFIG comcfg; - COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; - COMSTAT comstat; - DWORD size; - DWORD err; - - s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hsend) { - error_setg(errp, "Failed CreateEvent"); - goto fail; - } - s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hrecv) { - error_setg(errp, "Failed CreateEvent"); - goto fail; - } - - s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if (s->hcom == INVALID_HANDLE_VALUE) { - error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); - s->hcom = NULL; - goto fail; - } - - if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { - error_setg(errp, "Failed SetupComm"); - goto fail; - } - - ZeroMemory(&comcfg, sizeof(COMMCONFIG)); - size = sizeof(COMMCONFIG); - GetDefaultCommConfig(filename, &comcfg, &size); - comcfg.dcb.DCBlength = sizeof(DCB); - CommConfigDialog(filename, NULL, &comcfg); - - if (!SetCommState(s->hcom, &comcfg.dcb)) { - error_setg(errp, "Failed SetCommState"); - goto fail; - } - - if (!SetCommMask(s->hcom, EV_ERR)) { - error_setg(errp, "Failed SetCommMask"); - goto fail; - } - - cto.ReadIntervalTimeout = MAXDWORD; - if (!SetCommTimeouts(s->hcom, &cto)) { - error_setg(errp, "Failed SetCommTimeouts"); - goto fail; - } - - if (!ClearCommError(s->hcom, &err, &comstat)) { - error_setg(errp, "Failed ClearCommError"); - goto fail; - } - qemu_add_polling_cb(win_chr_poll, chr); - return 0; - - fail: - return -1; -} - -/* Called with chr_write_lock held. */ -static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1) -{ - WinChardev *s = WIN_CHARDEV(chr); - DWORD len, ret, size, err; - - len = len1; - ZeroMemory(&s->osend, sizeof(s->osend)); - s->osend.hEvent = s->hsend; - while (len > 0) { - if (s->hsend) - ret = WriteFile(s->hcom, buf, len, &size, &s->osend); - else - ret = WriteFile(s->hcom, buf, len, &size, NULL); - if (!ret) { - err = GetLastError(); - if (err == ERROR_IO_PENDING) { - ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); - if (ret) { - buf += size; - len -= size; - } else { - break; - } - } else { - break; - } - } else { - buf += size; - len -= size; - } - } - return len1 - len; -} - -static int win_chr_read_poll(Chardev *chr) -{ - WinChardev *s = WIN_CHARDEV(chr); - - s->max_size = qemu_chr_be_can_write(chr); - return s->max_size; -} - -static void win_chr_readfile(Chardev *chr) -{ - WinChardev *s = WIN_CHARDEV(chr); - - int ret, err; - uint8_t buf[CHR_READ_BUF_LEN]; - DWORD size; - - ZeroMemory(&s->orecv, sizeof(s->orecv)); - s->orecv.hEvent = s->hrecv; - ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); - if (!ret) { - err = GetLastError(); - if (err == ERROR_IO_PENDING) { - ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); - } - } - - if (size > 0) { - qemu_chr_be_write(chr, buf, size); - } -} - -static void win_chr_read(Chardev *chr) -{ - WinChardev *s = WIN_CHARDEV(chr); - - if (s->len > s->max_size) - s->len = s->max_size; - if (s->len == 0) - return; - - win_chr_readfile(chr); -} - -static int win_chr_poll(void *opaque) -{ - Chardev *chr = CHARDEV(opaque); - WinChardev *s = WIN_CHARDEV(opaque); - COMSTAT status; - DWORD comerr; - - ClearCommError(s->hcom, &comerr, &status); - if (status.cbInQue > 0) { - s->len = status.cbInQue; - win_chr_read_poll(chr); - win_chr_read(chr); - return 1; - } - return 0; -} - -static int win_chr_pipe_poll(void *opaque) -{ - Chardev *chr = CHARDEV(opaque); - WinChardev *s = WIN_CHARDEV(opaque); - DWORD size; - - PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); - if (size > 0) { - s->len = size; - win_chr_read_poll(chr); - win_chr_read(chr); - return 1; - } - return 0; -} - static int win_chr_pipe_init(Chardev *chr, const char *filename, Error **errp) { @@ -1790,30 +1565,6 @@ static void qemu_chr_open_pipe(Chardev *chr, } } -static void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out) -{ - WinChardev *s = WIN_CHARDEV(chr); - - s->skip_free = true; - s->hcom = fd_out; -} - -static void char_win_class_init(ObjectClass *oc, void *data) -{ - ChardevClass *cc = CHARDEV_CLASS(oc); - - cc->chr_write = win_chr_write; -} - -static const TypeInfo char_win_type_info = { - .name = TYPE_CHARDEV_WIN, - .parent = TYPE_CHARDEV, - .instance_size = sizeof(WinChardev), - .instance_finalize = char_win_finalize, - .class_init = char_win_class_init, - .abstract = true, -}; - static void qemu_chr_open_win_con(Chardev *chr, ChardevBackend *backend, bool *be_opened, @@ -4181,7 +3932,6 @@ static void register_types(void) { type_register_static(&char_type_info); #ifdef _WIN32 - type_register_static(&char_win_type_info); type_register_static(&char_win_stdio_type_info); #endif type_register_static(&char_socket_type_info); diff --git a/chardev/Makefile.objs b/chardev/Makefile.objs index d2f03dc5df..bdf5a112a7 100644 --- a/chardev/Makefile.objs +++ b/chardev/Makefile.objs @@ -4,3 +4,4 @@ chardev-obj-y += char-io.o chardev-obj-y += char-mux.o chardev-obj-y += char-null.o chardev-obj-y += char-ringbuf.o +chardev-obj-$(CONFIG_WIN32) += char-win.o diff --git a/chardev/char-win.h b/chardev/char-win.h new file mode 100644 index 0000000000..e91b5004ab --- /dev/null +++ b/chardev/char-win.h @@ -0,0 +1,30 @@ +#ifndef CHAR_WIN_H +#define CHAR_WIN_H + +#include "sysemu/char.h" + +typedef struct { + Chardev parent; + int max_size; + HANDLE hcom, hrecv, hsend; + OVERLAPPED orecv; + BOOL fpipe; + DWORD len; + + /* Protected by the Chardev chr_write_lock. */ + OVERLAPPED osend; + /* FIXME: file/console do not finalize */ + BOOL skip_free; +} WinChardev; + +#define NSENDBUF 2048 +#define NRECVBUF 2048 + +#define TYPE_CHARDEV_WIN "chardev-win" +#define WIN_CHARDEV(obj) OBJECT_CHECK(WinChardev, (obj), TYPE_CHARDEV_WIN) + +void qemu_chr_open_win_file(Chardev *chr, HANDLE fd_out); +int win_chr_init(Chardev *chr, const char *filename, Error **errp); +int win_chr_pipe_poll(void *opaque); + +#endif /* CHAR_WIN_H */