[Win32utils-devel] rb_w32_select function patch
Heesob Park
phasis at gmail.com
Mon Apr 28 06:53:26 EDT 2008
Hi, all
As you know, rb_w32_select don't work well with standard input.
Here is test code:
t = Thread.new {
while true
puts "printing a line"
sleep 2
end
}
gets
t.exit
puts "exiting"
Following is the first version of patch code of rb_w32_select function in
win32.c
It is inspired by cygwin select implementation code and adopted some code
from it.
The basic idea is creating thread for each file descriptor and wait events.
What's your thought about it?
Regards,
Park Heesob
/*========================================================================================*/
static HANDLE main_select_event=NULL;
static HANDLE *select_thread_list=NULL;
static struct {
int vk;
int val[4];
} keytable[] = {
/* N S C A */
{VK_LEFT, {1,1,1,1}},
{VK_RIGHT, {1,1,1,1}},
{VK_UP, {1,1,1,1}},
{VK_DOWN, {1,1,1,1}},
{VK_PRIOR, {1,1,1,1}},
{VK_NEXT, {1,1,1,1}},
{VK_HOME, {1,1,1,1}},
{VK_END, {1,1,1,1}},
{VK_INSERT, {1,1,1,1}},
{VK_DELETE, {1,1,1,1}},
{VK_F1, {1,1,0,0}},
{VK_F2, {1,1,0,0}},
{VK_F3, {1,1,0,0}},
{VK_F4, {1,1,0,0}},
{VK_F5, {1,1,0,0}},
{VK_F6, {1,1,1,0}},
{VK_F7, {1,1,0,0}},
{VK_F8, {1,1,0,0}},
{VK_F9, {1,1,0,0}},
{VK_F10, {1,1,0,0}},
{VK_F11, {1,0,0,0}},
{VK_F12, {1,0,0,0}},
{VK_NUMPAD5, {1,0,0,0}},
{VK_CLEAR, {1,0,0,0}},
{'6', {0,0,1,0}},
{0, {0,0,0,0}}
};
static int
is_non_ascii_key(INPUT_RECORD* irec)
{
#define NORMAL 0
#define SHIFT 1
#define CONTROL 2
#define ALT 3
int modifier_index = NORMAL;
int i;
if (irec->Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
modifier_index = SHIFT;
else if (irec->Event.KeyEvent.dwControlKeyState &
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
modifier_index = CONTROL;
else if (irec->Event.KeyEvent.dwControlKeyState &
(LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
modifier_index = ALT;
for (i = 0; keytable[i].vk; i++)
if (irec->Event.KeyEvent.wVirtualKeyCode == keytable[i].vk)
return keytable[i].val[modifier_index];
if (irec->Event.KeyEvent.uChar.AsciiChar) {
return 1;
}
return 0;
}
static DWORD WINAPI
select_read_thread(PVOID argp)
{
HANDLE fd_handle = (HANDLE)argp;
DWORD ret = 1;
DWORD mode = 0;
mode = 0;
GetConsoleMode(fd_handle,&mode);
if(mode!=0) {
// RealConsole Input
INPUT_RECORD irec;
DWORD events_read=0;
for(;;) {
ret = WaitForSingleObject(main_select_event,0);
if(ret!=WAIT_TIMEOUT) break;
if(!PeekConsoleInput(fd_handle,&irec,1,&events_read))
break;
if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown &&
(irec.Event.KeyEvent.uChar.AsciiChar || is_non_ascii_key(&irec))) {
return ret;
}
if(events_read>0)
ReadConsoleInput(fd_handle, &irec, 1, &events_read);
}
return ret;
}
return ret;
}
static DWORD WINAPI
select_write_thread(PVOID argp)
{
HANDLE fd_handle = (HANDLE)argp;
DWORD ret = 1;
DWORD mode = 0;
GetConsoleMode(fd_handle,&mode);
if(mode!=0) {
// RealConsole Output
return ret;
}
return ret;
}
long
rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
struct timeval *timeout)
{
long r;
fd_set file_rd;
fd_set file_wr;
#ifdef USE_INTERRUPT_WINSOCK
fd_set trap;
#endif /* USE_INTERRUPT_WINSOCK */
int file_nfds;
DWORD val;
int fd;
int i;
if (!NtSocketsInitialized) {
StartSockets();
}
r = 0;
if (rd && rd->fd_count > r) r = rd->fd_count;
if (wr && wr->fd_count > r) r = wr->fd_count;
if (ex && ex->fd_count > r) r = ex->fd_count;
if (nfds > r) nfds = r;
if (nfds == 0 && timeout) {
Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
return 0;
}
file_nfds = extract_file_fd(rd, &file_rd);
file_nfds += extract_file_fd(wr, &file_wr);
if (file_nfds)
{
main_select_event =
CreateEvent(NULL,TRUE,FALSE,"main_select_event");
if(main_select_event == NULL)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return -1;
}
select_thread_list = ALLOCA_N(HANDLE, file_nfds+1);
for(i=0; i<file_nfds; i++)
{
if(i<file_rd.fd_count) {
select_thread_list[i] = CreateThread(NULL,0,select_read_thread,
(PVOID)file_rd.fd_array[i],0,&val);
}
else {
select_thread_list[i] = CreateThread(NULL,0,select_write_thread,
(PVOID)file_wr.fd_array[i-file_rd.fd_count],0,&val);
}
if (select_thread_list[i] == NULL)
{
printf("CreateThread failed (%d)\n", GetLastError());
return -1;
}
}
select_thread_list[file_nfds] = interrupted_event;
r = WaitForMultipleObjects(file_nfds+1,select_thread_list,FALSE,
timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
if (!SetEvent(main_select_event) )
{
printf("SetEvent failed (%d)\n", GetLastError());
return -1;
}
CloseHandle(main_select_event);
if(r==WAIT_TIMEOUT)
return 0;
// assume normal files are always readable/writable
// fake read/write fd_set and return value
if (rd) *rd = file_rd;
if (wr) *wr = file_wr;
return file_nfds;
}
#if USE_INTERRUPT_WINSOCK
if (ex)
trap = *ex;
else
trap.fd_count = 0;
if (trap.fd_count < FD_SETSIZE)
trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
// else unable to catch interrupt.
ex = &trap;
#endif /* USE_INTERRUPT_WINSOCK */
RUBY_CRITICAL({
r = select(nfds, rd, wr, ex, timeout);
if (r == SOCKET_ERROR) {
errno = map_errno(WSAGetLastError());
}
});
return r;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/win32utils-devel/attachments/20080428/a9adc2e0/attachment-0001.html>
More information about the win32utils-devel
mailing list