1 /*
2  * event-win32.c
3  *
4  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5  *
6  * $Id: event-win32.c,v 1.1 2002/02/25 06:21:59 dugsong Exp $
7  */
8 
9 #include <windows.h>
10 #include <winsock.h>
11 
12 #include <err.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 #include "event.h"
17 
18 #define WT_EXECUTEINIOTHREAD	0x0000001
19 #define WT_EXECUTEONLYONCE	0x0000006
20 
21 typedef HANDLE (WINAPI *pCreateTimerQueue)(VOID);
22 typedef BOOL (WINAPI *pDeleteTimerQueue)(HANDLE TimerQueue);
23 typedef BOOL (WINAPI *pCreateTimerQueueTimer)(PHANDLE phNewTimer,
24     HANDLE TimerQueue, void CALLBACK (*pfnCallback)(PVOID, BOOL),
25     PVOID pvContext, DWORD DueTime, DWORD Period, ULONG Flags);
26 typedef BOOL (WINAPI *pDeleteTimerQueueTimer)(HANDLE TimerQueue, HANDLE Timer,
27     HANDLE CompletionEvent);
28 
29 static HINSTANCE		 lib_inst;
30 static HANDLE			 timer_queue;
31 static pCreateTimerQueue	 create_timer_queue;
32 static pDeleteTimerQueue	 delete_timer_queue;
33 static pCreateTimerQueueTimer	 create_timer;
34 static pDeleteTimerQueueTimer	 delete_timer;
35 
36 int	event_gotsig;
37 int	(*event_sigcb)(void);
38 
39 int
os_version(void)40 os_version(void)
41 {
42 	OSVERSIONINFO info;
43 
44 	info.dwOSVersionInfoSize = sizeof(info);
45 
46 	if (GetVersionEx(&info) == TRUE &&
47 	    info.dwPlatformId == VER_PLATFORM_WIN32_NT)
48 		return (info.dwMajorVersion);
49 
50 	return (32767);
51 }
52 
53 static int
timeval_to_ms(struct timeval * tv)54 timeval_to_ms(struct timeval *tv)
55 {
56 	return ((tv->tv_sec * 1000) + (tv->tv_usec / 1000));
57 }
58 
59 void
event_init(void)60 event_init(void)
61 {
62 	if (os_version() <= 4)
63 		errx(1, "this program must be run on Windows 2000 or greater");
64 
65 	lib_inst = LoadLibrary("kernel32.dll");
66 	if (lib_inst < (HINSTANCE)HINSTANCE_ERROR)
67 		errx(1, "couldn't load kernel32.dll");
68 
69 	create_timer_queue = (pCreateTimerQueue)GetProcAddress(lib_inst,
70 	    "CreateTimerQueue");
71 	delete_timer_queue = (pDeleteTimerQueue)GetProcAddress(lib_inst,
72 	    "DeleteTimerQueue");
73 	create_timer = (pCreateTimerQueueTimer)GetProcAddress(lib_inst,
74 	    "CreateTimerQueueTimer");
75 	delete_timer = (pDeleteTimerQueueTimer)GetProcAddress(lib_inst,
76 	    "DeleteTimerQueueTimer");
77 	if (create_timer_queue == NULL || delete_timer_queue == NULL ||
78 	    create_timer == NULL || delete_timer == NULL)
79 		errx(1, "couldn't map timer functions - not Windows 2000?");
80 
81 	timer_queue = create_timer_queue();
82 }
83 
84 void CALLBACK
event_callback(DWORD errcode,DWORD len,OVERLAPPED * overlap)85 event_callback(DWORD errcode, DWORD len, OVERLAPPED *overlap)
86 {
87 	struct event *ev = (struct event *)overlap->hEvent;
88 	struct event_iov eio;
89 
90 	eio.buf = ev->buf;
91 	eio.len = len;
92 
93 	ev->callback((int)&eio, ev->event, ev->arg);
94 }
95 
96 void
event_set(struct event * ev,int fd,short event,void (* callback)(int,short,void *),void * arg)97 event_set(struct event *ev, int fd, short event,
98     void (*callback)(int, short, void *), void *arg)
99 {
100 	memset(ev, 0, sizeof(*ev));
101 
102 	ev->handle = (HANDLE)fd;
103 	ev->overlap.hEvent = (HANDLE)ev;
104 	ev->event = event;
105 	ev->callback = callback;
106 	ev->arg = arg;
107 }
108 
109 int
event_add(struct event * ev,struct timeval * tv)110 event_add(struct event *ev, struct timeval *tv)
111 {
112 	if (tv != NULL || ev->event != EV_READ)
113 		return (-1);	/* XXX - UNIMPLEMENTED */
114 
115 	ReadFileEx(ev->handle, ev->buf, sizeof(ev->buf),
116 	    &ev->overlap, event_callback);
117 
118 	return (0);
119 }
120 
121 int
event_initialized(struct event * ev)122 event_initialized(struct event *ev)
123 {
124 	return (ev->handle != INVALID_HANDLE_VALUE);
125 }
126 
127 void
event_del(struct event * ev)128 event_del(struct event *ev)
129 {
130 	/* XXX - UNIMPLEMENTED */
131 }
132 
133 void
timeout_set(struct event * ev,void (* callback)(int,short,void *),void * arg)134 timeout_set(struct event *ev, void (*callback)(int, short, void *), void *arg)
135 {
136 	memset(ev, 0, sizeof(*ev));
137 
138 	ev->event = EV_TIMEOUT;
139 	ev->callback = callback;
140 	ev->arg = arg;
141 }
142 
143 void CALLBACK
timeout_callback(PVOID arg,BOOL TimerFired)144 timeout_callback(PVOID arg, BOOL TimerFired)
145 {
146 	struct event *ev = (struct event *)arg;
147 
148 	delete_timer(timer_queue, ev->handle, NULL);
149 	ev->handle = INVALID_HANDLE_VALUE;
150 
151 	ev->callback(-1, EV_TIMEOUT, ev->arg);
152 }
153 
154 void
timeout_add(struct event * ev,struct timeval * tv)155 timeout_add(struct event *ev, struct timeval *tv)
156 {
157 	if (create_timer(&ev->handle, timer_queue, timeout_callback, ev,
158 	    timeval_to_ms(tv), 0, WT_EXECUTEINIOTHREAD) == 0)
159 		errx(1, "CreateTimerQueueTimer failed");
160 }
161 
162 int
event_dispatch(void)163 event_dispatch(void)
164 {
165 	for (;;) {
166 		while (event_gotsig) {
167 			event_gotsig = 0;
168 			if (event_sigcb != NULL) {
169 				if ((*event_sigcb)() == -1) {
170 					delete_timer_queue(timer_queue);
171 					return (-1);
172 				}
173 			}
174 		}
175 		/* XXX - i'm a lazy bum */
176 		SleepEx(100, TRUE);
177 	}
178 	return (0);
179 }
180