@@ -27,28 +27,217 @@ enum _dispatch_windows_port {
2727DISPATCH_PORT_TIMER_CLOCK_WALL ,
2828DISPATCH_PORT_TIMER_CLOCK_UPTIME ,
2929DISPATCH_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+
34158bool
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
41196void
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
47205bool
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 );
222411break ;
223412
413+ case DISPATCH_PORT_FILE_HANDLE :
414+ _dispatch_event_merge_file_handle ();
415+ break ;
416+
224417default :
225418DISPATCH_INTERNAL_CRASH (ulCompletionKey ,
226419"unsupported completion key" );
0 commit comments