Message ID | 5cef88f5cfc195f16583a0dda5cf16670cc0c0db.1296493772.git.chouteau@adacore.com |
---|---|
State | New |
Headers | show |
On 01/31/2011 06:09 PM, Fabien Chouteau wrote: > Simple implementation of an stdio char device on Windows. > > Signed-off-by: Fabien Chouteau<chouteau@adacore.com> > --- > qemu-char.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 171 insertions(+), 0 deletions(-) > > diff --git a/qemu-char.c b/qemu-char.c > index edc9ad6..c18e668 100644 > --- a/qemu-char.c > +++ b/qemu-char.c > @@ -1436,6 +1436,11 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) > > #else /* _WIN32 */ > > +#define STDIO_MAX_CLIENTS 2 Why 2? If it were 1, you could use a single definition for Unix and Win32. > + > +static int stdio_nb_clients; > +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; > + > typedef struct { > int max_size; > HANDLE hcom, hrecv, hsend; > @@ -1788,6 +1793,171 @@ static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) > > return qemu_chr_open_win_file(fd_out); > } > + > +static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) > +{ > + HANDLE *Output = GetStdHandle(STD_OUTPUT_HANDLE); Please use Hungarian notation for Windows objects, i.e. hStdOut. > + DWORD size; > + int len1; > + > + len1 = len; > + > + while (len1> 0) { > + if (!WriteFile(Output, buf, len1,&size, NULL)) { > + break; > + } > + buf += size; > + len1 -= size; > + } > + > + return len - len1; > +} > + > +static HANDLE *Input; and hStdIn > + > +static void win_stdio_wait_func(void *opaque) > +{ > + CharDriverState *chr = opaque; > + INPUT_RECORD buf[4]; > + int ret; > + DWORD size; > + int i; > + > + ret = ReadConsoleInput(Input, buf, sizeof(buf)/sizeof(*buf),&size); > + > + if (!ret) { > + /* Avoid error storm */ > + qemu_del_wait_object(Input, NULL, NULL); > + return; > + } > + > + for (i = 0; i< size; i++) { > + KEY_EVENT_RECORD *kev =&buf[i].Event.KeyEvent; > + > + if (buf[i].EventType == KEY_EVENT&& kev->bKeyDown) { > + int j; > + if (kev->uChar.AsciiChar != 0) { > + for (j = 0; j< kev->wRepeatCount; j++) > + if (qemu_chr_can_read(chr)) { > + uint8_t c = kev->uChar.AsciiChar; > + qemu_chr_read(chr,&c, 1); > + } > + } > + } > + } > +} > + > +static HANDLE InputReadyEvent; > +static HANDLE InputDoneEvent; > +static uint8_t InputBuf; and hInputReadyEvent, hInputDoneEvent. Stuff that is not Windows objects should use underscores as in win_stdio_buf. > + > +static DWORD WINAPI win_stdio_thread(LPVOID param) > +{ > + int ret; > + DWORD size; > + > + while (1) { > + > + /* Wait for one byte */ > + ret = ReadFile(Input,&InputBuf, 1,&size, NULL); > + > + /* Exit in case of error, continue if nothing read */ > + if (!ret) { > + break; > + } > + if (!size) { > + continue; > + } > + > + /* Some terminal emulator returns \r\n for Enter, just pass \n */ > + if (InputBuf == '\r') { > + continue; > + } > + > + /* Signal the main thread and wait until the byte was eaten */ > + if (!SetEvent(InputReadyEvent)) { > + break; > + } > + if (WaitForSingleObject(InputDoneEvent, INFINITE) != WAIT_OBJECT_0) { > + break; > + } > + } > + > + qemu_del_wait_object(InputReadyEvent, NULL, NULL); > + return 0; > +} > + > +static void win_stdio_thread_wait_func(void *opaque) > +{ > + CharDriverState *chr = opaque; > + > + if (qemu_chr_can_read(chr)) { > + qemu_chr_read(chr,&InputBuf, 1); > + } > + > + SetEvent(InputDoneEvent); > +} > + > +static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) > +{ > + CharDriverState *chr; > + DWORD mode; > + int is_console = 0; > + > + Input = GetStdHandle(STD_INPUT_HANDLE); > + if (Input == INVALID_HANDLE_VALUE) { > + fprintf(stderr, "cannot open stdio: invalid handle\n"); > + exit(1); > + } > + > + is_console = GetConsoleMode(Input,&mode) != 0; > + > + if (stdio_nb_clients>= STDIO_MAX_CLIENTS > + || ((display_type != DT_NOGRAPHIC)&& (stdio_nb_clients != 0))) { > + return NULL; > + } > + > + chr = qemu_mallocz(sizeof(CharDriverState)); > + if (!chr) { > + return NULL; > + } > + > + chr->chr_write = win_stdio_write; > + > + if (stdio_nb_clients == 0) { > + if (is_console) { > + if (qemu_add_wait_object(InputReadyEvent, > + win_stdio_thread_wait_func, chr)) { > + fprintf(stderr, "qemu_add_wait_object: failed\n"); > + } > + } else { > + DWORD id; > + HANDLE *InputThread; > + > + InputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); > + InputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); > + InputThread = CreateThread(NULL, 0, win_stdio_thread, chr, 0,&id); > + > + if (InputThread == INVALID_HANDLE_VALUE > + || InputReadyEvent == INVALID_HANDLE_VALUE > + || InputDoneEvent == INVALID_HANDLE_VALUE) { > + fprintf(stderr, "cannot create stdio thread or event\n"); > + exit(1); > + } > + if (qemu_add_wait_object(Input, win_stdio_thread_wait_func, chr)) { > + fprintf(stderr, "qemu_add_wait_object: failed\n"); > + } > + } > + } > + > + stdio_clients[stdio_nb_clients++] = chr; > + if (stdio_nb_clients == 1 && is_console) { > + /* set the terminal in raw mode */ > + /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ > + SetConsoleMode(Input, ENABLE_PROCESSED_INPUT); > + } > + return chr; > +} > #endif /* !_WIN32 */ > > /***********************************************************/ > @@ -2477,6 +2647,7 @@ static const struct { > { .name = "pipe", .open = qemu_chr_open_win_pipe }, > { .name = "console", .open = qemu_chr_open_win_con }, > { .name = "serial", .open = qemu_chr_open_win }, > + { .name = "stdio", .open = qemu_chr_open_win_stdio }, > #else > { .name = "file", .open = qemu_chr_open_file_out }, > { .name = "pipe", .open = qemu_chr_open_pipe }, Otherwise looks good, can you wait for http://permalink.gmane.org/gmane.comp.emulators.qemu/88490 to be merged so that you can add the set_echo implementation too? Thanks! Paolo
On 01/31/2011 06:43 PM, Paolo Bonzini wrote: > On 01/31/2011 06:09 PM, Fabien Chouteau wrote: >> Simple implementation of an stdio char device on Windows. >> >> Signed-off-by: Fabien Chouteau<chouteau@adacore.com> >> --- >> qemu-char.c | 171 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 1 files changed, 171 insertions(+), 0 deletions(-) >> >> diff --git a/qemu-char.c b/qemu-char.c >> index edc9ad6..c18e668 100644 >> --- a/qemu-char.c >> +++ b/qemu-char.c >> @@ -1436,6 +1436,11 @@ static CharDriverState >> *qemu_chr_open_pp(QemuOpts *opts) >> >> #else /* _WIN32 */ >> >> +#define STDIO_MAX_CLIENTS 2 > > Why 2? If it were 1, you could use a single definition for Unix and > Win32. > >> + >> +static int stdio_nb_clients; >> +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; >> + >> typedef struct { >> int max_size; >> HANDLE hcom, hrecv, hsend; >> @@ -1788,6 +1793,171 @@ static CharDriverState >> *qemu_chr_open_win_file_out(QemuOpts *opts) >> >> return qemu_chr_open_win_file(fd_out); >> } >> + >> +static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, >> int len) >> +{ >> + HANDLE *Output = GetStdHandle(STD_OUTPUT_HANDLE); > > Please use Hungarian notation for Windows objects, i.e. hStdOut. > >> + DWORD size; >> + int len1; >> + >> + len1 = len; >> + >> + while (len1> 0) { >> + if (!WriteFile(Output, buf, len1,&size, NULL)) { >> + break; >> + } >> + buf += size; >> + len1 -= size; >> + } >> + >> + return len - len1; >> +} >> + >> +static HANDLE *Input; > > and hStdIn > >> + >> +static void win_stdio_wait_func(void *opaque) >> +{ >> + CharDriverState *chr = opaque; >> + INPUT_RECORD buf[4]; >> + int ret; >> + DWORD size; >> + int i; >> + >> + ret = ReadConsoleInput(Input, buf, sizeof(buf)/sizeof(*buf),&size); >> + >> + if (!ret) { >> + /* Avoid error storm */ >> + qemu_del_wait_object(Input, NULL, NULL); >> + return; >> + } >> + >> + for (i = 0; i< size; i++) { >> + KEY_EVENT_RECORD *kev =&buf[i].Event.KeyEvent; >> + >> + if (buf[i].EventType == KEY_EVENT&& kev->bKeyDown) { >> + int j; >> + if (kev->uChar.AsciiChar != 0) { >> + for (j = 0; j< kev->wRepeatCount; j++) >> + if (qemu_chr_can_read(chr)) { >> + uint8_t c = kev->uChar.AsciiChar; >> + qemu_chr_read(chr,&c, 1); >> + } >> + } >> + } >> + } >> +} >> + >> +static HANDLE InputReadyEvent; >> +static HANDLE InputDoneEvent; >> +static uint8_t InputBuf; > > and hInputReadyEvent, hInputDoneEvent. Stuff that is not Windows > objects should use underscores as in win_stdio_buf. > >> + >> +static DWORD WINAPI win_stdio_thread(LPVOID param) >> +{ >> + int ret; >> + DWORD size; >> + >> + while (1) { >> + >> + /* Wait for one byte */ >> + ret = ReadFile(Input,&InputBuf, 1,&size, NULL); >> + >> + /* Exit in case of error, continue if nothing read */ >> + if (!ret) { >> + break; >> + } >> + if (!size) { >> + continue; >> + } >> + >> + /* Some terminal emulator returns \r\n for Enter, just pass >> \n */ >> + if (InputBuf == '\r') { >> + continue; >> + } >> + >> + /* Signal the main thread and wait until the byte was eaten */ >> + if (!SetEvent(InputReadyEvent)) { >> + break; >> + } >> + if (WaitForSingleObject(InputDoneEvent, INFINITE) != >> WAIT_OBJECT_0) { >> + break; >> + } >> + } >> + >> + qemu_del_wait_object(InputReadyEvent, NULL, NULL); >> + return 0; >> +} >> + >> +static void win_stdio_thread_wait_func(void *opaque) >> +{ >> + CharDriverState *chr = opaque; >> + >> + if (qemu_chr_can_read(chr)) { >> + qemu_chr_read(chr,&InputBuf, 1); >> + } >> + >> + SetEvent(InputDoneEvent); >> +} >> + >> +static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) >> +{ >> + CharDriverState *chr; >> + DWORD mode; >> + int is_console = 0; >> + >> + Input = GetStdHandle(STD_INPUT_HANDLE); >> + if (Input == INVALID_HANDLE_VALUE) { >> + fprintf(stderr, "cannot open stdio: invalid handle\n"); >> + exit(1); >> + } >> + >> + is_console = GetConsoleMode(Input,&mode) != 0; >> + >> + if (stdio_nb_clients>= STDIO_MAX_CLIENTS >> + || ((display_type != DT_NOGRAPHIC)&& (stdio_nb_clients != >> 0))) { >> + return NULL; >> + } >> + >> + chr = qemu_mallocz(sizeof(CharDriverState)); >> + if (!chr) { >> + return NULL; >> + } >> + >> + chr->chr_write = win_stdio_write; >> + >> + if (stdio_nb_clients == 0) { >> + if (is_console) { >> + if (qemu_add_wait_object(InputReadyEvent, >> + win_stdio_thread_wait_func, >> chr)) { >> + fprintf(stderr, "qemu_add_wait_object: failed\n"); >> + } >> + } else { >> + DWORD id; >> + HANDLE *InputThread; >> + >> + InputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); >> + InputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); >> + InputThread = CreateThread(NULL, 0, win_stdio_thread, >> chr, 0,&id); >> + >> + if (InputThread == INVALID_HANDLE_VALUE >> + || InputReadyEvent == INVALID_HANDLE_VALUE >> + || InputDoneEvent == INVALID_HANDLE_VALUE) { >> + fprintf(stderr, "cannot create stdio thread or >> event\n"); >> + exit(1); >> + } >> + if (qemu_add_wait_object(Input, >> win_stdio_thread_wait_func, chr)) { >> + fprintf(stderr, "qemu_add_wait_object: failed\n"); >> + } >> + } >> + } >> + >> + stdio_clients[stdio_nb_clients++] = chr; >> + if (stdio_nb_clients == 1 && is_console) { >> + /* set the terminal in raw mode */ >> + /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ >> + SetConsoleMode(Input, ENABLE_PROCESSED_INPUT); >> + } >> + return chr; >> +} >> #endif /* !_WIN32 */ >> >> /***********************************************************/ >> @@ -2477,6 +2647,7 @@ static const struct { >> { .name = "pipe", .open = qemu_chr_open_win_pipe }, >> { .name = "console", .open = qemu_chr_open_win_con }, >> { .name = "serial", .open = qemu_chr_open_win }, >> + { .name = "stdio", .open = qemu_chr_open_win_stdio }, >> #else >> { .name = "file", .open = qemu_chr_open_file_out }, >> { .name = "pipe", .open = qemu_chr_open_pipe }, > > Otherwise looks good, can you wait for > http://permalink.gmane.org/gmane.comp.emulators.qemu/88490 to be > merged so that you can add the set_echo implementation too? OK, I can wait. When do you expect your patches to be ready? Thanks for your comments,
On 02/01/2011 12:24 PM, Fabien Chouteau wrote: >> Otherwise looks good, can you wait for >> http://permalink.gmane.org/gmane.comp.emulators.qemu/88490 to be >> merged so that you can add the set_echo implementation too? > > OK, I can wait. When do you expect your patches to be ready? They are, I'm waiting for someone to pick them. Paolo
diff --git a/qemu-char.c b/qemu-char.c index edc9ad6..c18e668 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1436,6 +1436,11 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) #else /* _WIN32 */ +#define STDIO_MAX_CLIENTS 2 + +static int stdio_nb_clients; +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; + typedef struct { int max_size; HANDLE hcom, hrecv, hsend; @@ -1788,6 +1793,171 @@ static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) return qemu_chr_open_win_file(fd_out); } + +static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + HANDLE *Output = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD size; + int len1; + + len1 = len; + + while (len1 > 0) { + if (!WriteFile(Output, buf, len1, &size, NULL)) { + break; + } + buf += size; + len1 -= size; + } + + return len - len1; +} + +static HANDLE *Input; + +static void win_stdio_wait_func(void *opaque) +{ + CharDriverState *chr = opaque; + INPUT_RECORD buf[4]; + int ret; + DWORD size; + int i; + + ret = ReadConsoleInput(Input, buf, sizeof(buf)/sizeof(*buf), &size); + + if (!ret) { + /* Avoid error storm */ + qemu_del_wait_object(Input, NULL, NULL); + return; + } + + for (i = 0; i < size; i++) { + KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; + + if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { + int j; + if (kev->uChar.AsciiChar != 0) { + for (j = 0; j < kev->wRepeatCount; j++) + if (qemu_chr_can_read(chr)) { + uint8_t c = kev->uChar.AsciiChar; + qemu_chr_read(chr, &c, 1); + } + } + } + } +} + +static HANDLE InputReadyEvent; +static HANDLE InputDoneEvent; +static uint8_t InputBuf; + +static DWORD WINAPI win_stdio_thread(LPVOID param) +{ + int ret; + DWORD size; + + while (1) { + + /* Wait for one byte */ + ret = ReadFile(Input, &InputBuf, 1, &size, NULL); + + /* Exit in case of error, continue if nothing read */ + if (!ret) { + break; + } + if (!size) { + continue; + } + + /* Some terminal emulator returns \r\n for Enter, just pass \n */ + if (InputBuf == '\r') { + continue; + } + + /* Signal the main thread and wait until the byte was eaten */ + if (!SetEvent(InputReadyEvent)) { + break; + } + if (WaitForSingleObject(InputDoneEvent, INFINITE) != WAIT_OBJECT_0) { + break; + } + } + + qemu_del_wait_object(InputReadyEvent, NULL, NULL); + return 0; +} + +static void win_stdio_thread_wait_func(void *opaque) +{ + CharDriverState *chr = opaque; + + if (qemu_chr_can_read(chr)) { + qemu_chr_read(chr, &InputBuf, 1); + } + + SetEvent(InputDoneEvent); +} + +static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) +{ + CharDriverState *chr; + DWORD mode; + int is_console = 0; + + Input = GetStdHandle(STD_INPUT_HANDLE); + if (Input == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot open stdio: invalid handle\n"); + exit(1); + } + + is_console = GetConsoleMode(Input, &mode) != 0; + + if (stdio_nb_clients >= STDIO_MAX_CLIENTS + || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { + return NULL; + } + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) { + return NULL; + } + + chr->chr_write = win_stdio_write; + + if (stdio_nb_clients == 0) { + if (is_console) { + if (qemu_add_wait_object(InputReadyEvent, + win_stdio_thread_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } else { + DWORD id; + HANDLE *InputThread; + + InputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + InputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + InputThread = CreateThread(NULL, 0, win_stdio_thread, chr, 0, &id); + + if (InputThread == INVALID_HANDLE_VALUE + || InputReadyEvent == INVALID_HANDLE_VALUE + || InputDoneEvent == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot create stdio thread or event\n"); + exit(1); + } + if (qemu_add_wait_object(Input, win_stdio_thread_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } + } + + stdio_clients[stdio_nb_clients++] = chr; + if (stdio_nb_clients == 1 && is_console) { + /* set the terminal in raw mode */ + /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ + SetConsoleMode(Input, ENABLE_PROCESSED_INPUT); + } + return chr; +} #endif /* !_WIN32 */ /***********************************************************/ @@ -2477,6 +2647,7 @@ static const struct { { .name = "pipe", .open = qemu_chr_open_win_pipe }, { .name = "console", .open = qemu_chr_open_win_con }, { .name = "serial", .open = qemu_chr_open_win }, + { .name = "stdio", .open = qemu_chr_open_win_stdio }, #else { .name = "file", .open = qemu_chr_open_file_out }, { .name = "pipe", .open = qemu_chr_open_pipe },
Simple implementation of an stdio char device on Windows. Signed-off-by: Fabien Chouteau <chouteau@adacore.com> --- qemu-char.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 171 insertions(+), 0 deletions(-)