Skip to content

Commit 2559da4

Browse files
compnerdrokhinip
authored andcommitted
windows: add initial cut of file sources
This adds support for regular file types as an event source for dispatch. This leaves much to be desired (pipes, character devices), but improves the overall coverage. A number of additional tests now pass on Windows. Signed-off-by: Kim Topley <[email protected]>
1 parent ccef90b commit 2559da4

File tree

2 files changed

+201
-8
lines changed

2 files changed

+201
-8
lines changed

src/event/event_windows.c

Lines changed: 201 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,217 @@ enum _dispatch_windows_port {
2727
DISPATCH_PORT_TIMER_CLOCK_WALL,
2828
DISPATCH_PORT_TIMER_CLOCK_UPTIME,
2929
DISPATCH_PORT_TIMER_CLOCK_MONOTONIC,
30+
DISPATCH_PORT_FILE_HANDLE,
3031
};
3132

3233
#pragma mark dispatch_unote_t
3334

35+
typedef struct dispatch_muxnote_s {
36+
LIST_ENTRY(dispatch_muxnote_s) dmn_list;
37+
dispatch_unote_ident_t dmn_ident;
38+
int8_t dmn_filter;
39+
enum _dispatch_muxnote_handle_type {
40+
DISPATCH_MUXNOTE_HANDLE_TYPE_INVALID,
41+
DISPATCH_MUXNOTE_HANDLE_TYPE_FILE,
42+
} dmn_handle_type;
43+
} *dispatch_muxnote_t;
44+
45+
static LIST_HEAD(dispatch_muxnote_bucket_s, dispatch_muxnote_s)
46+
_dispatch_sources[DSL_HASH_SIZE];
47+
48+
static SRWLOCK _dispatch_file_handles_lock = SRWLOCK_INIT;
49+
static LIST_HEAD(, dispatch_unote_linkage_s) _dispatch_file_handles;
50+
51+
DISPATCH_ALWAYS_INLINE
52+
static inline struct dispatch_muxnote_bucket_s *
53+
_dispatch_unote_muxnote_bucket(uint32_t ident)
54+
{
55+
return &_dispatch_sources[DSL_HASH(ident)];
56+
}
57+
58+
DISPATCH_ALWAYS_INLINE
59+
static inline dispatch_muxnote_t
60+
_dispatch_unote_muxnote_find(struct dispatch_muxnote_bucket_s *dmb,
61+
dispatch_unote_ident_t ident, int8_t filter)
62+
{
63+
dispatch_muxnote_t dmn;
64+
if (filter == EVFILT_WRITE) filter = EVFILT_READ;
65+
LIST_FOREACH(dmn, dmb, dmn_list) {
66+
if (dmn->dmn_ident == ident && dmn->dmn_filter == filter) {
67+
break;
68+
}
69+
}
70+
return dmn;
71+
}
72+
73+
static dispatch_muxnote_t
74+
_dispatch_muxnote_create(dispatch_unote_t du)
75+
{
76+
dispatch_muxnote_t dmn;
77+
int8_t filter = du._du->du_filter;
78+
HANDLE handle = (HANDLE)du._du->du_ident;
79+
80+
dmn = _dispatch_calloc(1, sizeof(*dmn));
81+
if (dmn == NULL) {
82+
DISPATCH_INTERNAL_CRASH(0, "_dispatch_calloc");
83+
}
84+
dmn->dmn_ident = (dispatch_unote_ident_t)handle;
85+
dmn->dmn_filter = filter;
86+
87+
switch (filter) {
88+
case EVFILT_SIGNAL:
89+
WIN_PORT_ERROR();
90+
91+
case EVFILT_WRITE:
92+
case EVFILT_READ:
93+
switch (GetFileType(handle)) {
94+
case FILE_TYPE_UNKNOWN:
95+
// ensure that an invalid handle was not passed
96+
(void)dispatch_assume(GetLastError() == NO_ERROR);
97+
DISPATCH_INTERNAL_CRASH(0, "unknown handle type");
98+
99+
case FILE_TYPE_REMOTE:
100+
DISPATCH_INTERNAL_CRASH(0, "unused handle type");
101+
102+
case FILE_TYPE_CHAR:
103+
// The specified file is a character file, typically a
104+
// LPT device or a console.
105+
WIN_PORT_ERROR();
106+
107+
case FILE_TYPE_DISK:
108+
// The specified file is a disk file
109+
dmn->dmn_handle_type =
110+
DISPATCH_MUXNOTE_HANDLE_TYPE_FILE;
111+
break;
112+
113+
case FILE_TYPE_PIPE:
114+
// The specified file is a socket, a named pipe, or an
115+
// anonymous pipe.
116+
WIN_PORT_ERROR();
117+
}
118+
119+
break;
120+
121+
default:
122+
DISPATCH_INTERNAL_CRASH(0, "unexpected filter");
123+
}
124+
125+
126+
return dmn;
127+
}
128+
129+
static void
130+
_dispatch_muxnote_dispose(dispatch_muxnote_t dmn)
131+
{
132+
free(dmn);
133+
}
134+
135+
DISPATCH_ALWAYS_INLINE
136+
static BOOL
137+
_dispatch_io_trigger(dispatch_muxnote_t dmn)
138+
{
139+
BOOL bSuccess;
140+
141+
switch (dmn->dmn_handle_type) {
142+
case DISPATCH_MUXNOTE_HANDLE_TYPE_INVALID:
143+
DISPATCH_INTERNAL_CRASH(0, "invalid handle");
144+
145+
case DISPATCH_MUXNOTE_HANDLE_TYPE_FILE:
146+
bSuccess = PostQueuedCompletionStatus(hPort, 0,
147+
(ULONG_PTR)DISPATCH_PORT_FILE_HANDLE, NULL);
148+
if (bSuccess == FALSE) {
149+
DISPATCH_INTERNAL_CRASH(GetLastError(),
150+
"PostQueuedCompletionStatus");
151+
}
152+
break;
153+
}
154+
155+
return bSuccess;
156+
}
157+
34158
bool
35-
_dispatch_unote_register_muxed(dispatch_unote_t du DISPATCH_UNUSED)
159+
_dispatch_unote_register_muxed(dispatch_unote_t du)
36160
{
37-
WIN_PORT_ERROR();
38-
return false;
161+
struct dispatch_muxnote_bucket_s *dmb;
162+
dispatch_muxnote_t dmn;
163+
164+
dmb = _dispatch_unote_muxnote_bucket(du._du->du_ident);
165+
dmn = _dispatch_unote_muxnote_find(dmb, du._du->du_ident,
166+
du._du->du_filter);
167+
if (dmn) {
168+
WIN_PORT_ERROR();
169+
} else {
170+
dmn = _dispatch_muxnote_create(du);
171+
if (dmn) {
172+
if (_dispatch_io_trigger(dmn) == FALSE) {
173+
_dispatch_muxnote_dispose(dmn);
174+
dmn = NULL;
175+
} else {
176+
LIST_INSERT_HEAD(dmb, dmn, dmn_list);
177+
}
178+
}
179+
}
180+
181+
if (dmn) {
182+
dispatch_unote_linkage_t dul = _dispatch_unote_get_linkage(du);
183+
184+
AcquireSRWLockExclusive(&_dispatch_file_handles_lock);
185+
LIST_INSERT_HEAD(&_dispatch_file_handles, dul, du_link);
186+
ReleaseSRWLockExclusive(&_dispatch_file_handles_lock);
187+
188+
dul->du_muxnote = dmn;
189+
_dispatch_unote_state_set(du, DISPATCH_WLH_ANON,
190+
DU_STATE_ARMED);
191+
}
192+
193+
return dmn != NULL;
39194
}
40195

41196
void
42-
_dispatch_unote_resume_muxed(dispatch_unote_t du DISPATCH_UNUSED)
197+
_dispatch_unote_resume_muxed(dispatch_unote_t du)
43198
{
44-
WIN_PORT_ERROR();
199+
dispatch_unote_linkage_t dul = _dispatch_unote_get_linkage(du);
200+
dispatch_muxnote_t dmn = dul->du_muxnote;
201+
dispatch_assert(_dispatch_unote_registered(du));
202+
_dispatch_io_trigger(dmn);
45203
}
46204

47205
bool
48-
_dispatch_unote_unregister_muxed(dispatch_unote_t du DISPATCH_UNUSED)
206+
_dispatch_unote_unregister_muxed(dispatch_unote_t du)
49207
{
50-
WIN_PORT_ERROR();
51-
return false;
208+
dispatch_unote_linkage_t dul = _dispatch_unote_get_linkage(du);
209+
dispatch_muxnote_t dmn = dul->du_muxnote;
210+
211+
AcquireSRWLockExclusive(&_dispatch_file_handles_lock);
212+
LIST_REMOVE(dul, du_link);
213+
_LIST_TRASH_ENTRY(dul, du_link);
214+
ReleaseSRWLockExclusive(&_dispatch_file_handles_lock);
215+
dul->du_muxnote = NULL;
216+
217+
LIST_REMOVE(dmn, dmn_list);
218+
_dispatch_muxnote_dispose(dmn);
219+
220+
_dispatch_unote_state_set(du, DU_STATE_UNREGISTERED);
221+
return true;
222+
}
223+
224+
static void
225+
_dispatch_event_merge_file_handle()
226+
{
227+
dispatch_unote_linkage_t dul, dul_next;
228+
229+
AcquireSRWLockExclusive(&_dispatch_file_handles_lock);
230+
LIST_FOREACH_SAFE(dul, &_dispatch_file_handles, du_link, dul_next) {
231+
dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul);
232+
233+
// consumed by dux_merge_evt()
234+
_dispatch_retain_unote_owner(du);
235+
dispatch_assert(dux_needs_rearm(du._du));
236+
_dispatch_unote_state_clear_bit(du, DU_STATE_ARMED);
237+
os_atomic_store2o(du._dr, ds_pending_data, ~1, relaxed);
238+
dux_merge_evt(du._du, EV_ADD | EV_ENABLE | EV_DISPATCH, 1, 0);
239+
}
240+
ReleaseSRWLockExclusive(&_dispatch_file_handles_lock);
52241
}
53242

54243
#pragma mark timers
@@ -221,6 +410,10 @@ _dispatch_event_loop_drain(uint32_t flags)
221410
_dispatch_event_merge_timer(DISPATCH_CLOCK_MONOTONIC);
222411
break;
223412

413+
case DISPATCH_PORT_FILE_HANDLE:
414+
_dispatch_event_merge_file_handle();
415+
break;
416+
224417
default:
225418
DISPATCH_INTERNAL_CRASH(ulCompletionKey,
226419
"unsupported completion key");
File renamed without changes.

0 commit comments

Comments
 (0)