2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
4 * FILE: dll/win32/ws2_32_new/src/async.c
5 * PURPOSE: Async Block Object and Async Thread Management
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
13 /* DATA **********************************************************************/
15 BOOLEAN WsAsyncThreadInitialized
;
16 LONG WsAsyncTaskHandle
;
17 PLIST_ENTRY WsAsyncQueue
;
18 CRITICAL_SECTION WsAsyncCritSect
;
20 HANDLE WsAsyncCurrentTaskHandle
;
21 HANDLE WsAsyncCancelledTaskHandle
;
22 HINSTANCE WsAsyncDllHandle
;
24 #define WsAsyncLock() EnterCriticalSection(&WsAsyncCritSect);
25 #define WsAsyncUnlock() LeaveCriticalSection(&WsAsyncCritSect);
27 /* FUNCTIONS *****************************************************************/
31 WsAsyncGlobalInitialize(VOID
)
33 /* Initialize the async lock */
34 InitializeCriticalSection(&WsAsyncCritSect
);
39 WsAsyncGlobalTerminate(VOID
)
41 /* Destroy the async lock */
42 DeleteCriticalSection(&WsAsyncCritSect
);
48 BytesInHostent(PHOSTENT Hostent
)
53 /* Start with the static stuff */
54 Bytes
= sizeof(HOSTENT
) + strlen(Hostent
->h_name
) + sizeof(CHAR
);
56 /* Add 2 pointers for the list-terminators */
57 Bytes
+= 2 * sizeof(ULONG_PTR
);
59 /* Now loop for the alises */
60 for (i
= 0; Hostent
->h_aliases
[i
]; i
++)
62 /* Add the alias size, plus the space its pointer takes */
63 Bytes
+= strlen(Hostent
->h_aliases
[i
]) + sizeof(CHAR
) + sizeof(ULONG_PTR
);
66 /* Now loop for the hostnames */
67 for (i
= 0; Hostent
->h_addr_list
[i
]; i
++)
69 /* Add the alias size, plus the space its pointer takes */
70 Bytes
+= Hostent
->h_length
+ sizeof(ULONG_PTR
);
73 /* Align to 8 bytes */
74 return (Bytes
+ 7) & ~7;
79 BytesInServent(PSERVENT Servent
)
84 /* Start with the static stuff */
85 Bytes
= sizeof(SERVENT
) +
86 strlen(Servent
->s_name
) + sizeof(CHAR
) +
87 strlen(Servent
->s_proto
) + sizeof(CHAR
);
89 /* Add 1 pointers for the list terminator */
90 Bytes
+= sizeof(ULONG_PTR
);
92 /* Now loop for the alises */
93 for (i
= 0; Servent
->s_aliases
[i
]; i
++)
95 /* Add the alias size, plus the space its pointer takes */
96 Bytes
+= strlen(Servent
->s_aliases
[i
]) + sizeof(CHAR
) + sizeof(ULONG_PTR
);
105 BytesInProtoent(PPROTOENT Protoent
)
110 /* Start with the static stuff */
111 Bytes
= sizeof(SERVENT
) + strlen(Protoent
->p_name
) + sizeof(CHAR
);
113 /* Add 1 pointers for the list terminator */
114 Bytes
+= sizeof(ULONG_PTR
);
116 /* Now loop for the alises */
117 for (i
= 0; Protoent
->p_aliases
[i
]; i
++)
119 /* Add the alias size, plus the space its pointer takes */
120 Bytes
+= strlen(Protoent
->p_aliases
[i
]) + sizeof(CHAR
) + sizeof(ULONG_PTR
);
129 CopyHostentToBuffer(IN PCHAR Buffer
,
133 SIZE_T BufferSize
, CurrentSize
, NameSize
;
135 DWORD Aliases
= 0, Names
= 0;
137 PHOSTENT ReturnedHostent
= (PHOSTENT
)Buffer
;
139 /* Determine the buffer size required */
140 BufferSize
= BytesInHostent(Hostent
);
142 /* Check which size to use */
143 if ((DWORD
)BufferLength
> BufferSize
)
145 /* Zero the buffer */
146 RtlZeroMemory(Buffer
, BufferSize
);
150 /* Zero the buffer */
151 RtlZeroMemory(Buffer
, BufferLength
);
154 /* Start with the raw Hostent */
155 CurrentSize
= sizeof(HOSTENT
);
157 /* Return the size needed now */
158 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
160 /* Copy the Hostent and initialize it */
161 CopyMemory(p
, Hostent
, sizeof(HOSTENT
));
162 p
= Buffer
+ CurrentSize
;
163 ReturnedHostent
->h_name
= NULL
;
164 ReturnedHostent
->h_aliases
= NULL
;
165 ReturnedHostent
->h_addr_list
= NULL
;
167 /* Find out how many aliases there are */
168 while (Hostent
->h_aliases
[Aliases
])
170 /* Increase the alias count */
174 /* Add the aliases to the size, and validate it */
175 CurrentSize
+= (Aliases
+ 1) * sizeof(ULONG_PTR
);
176 if (CurrentSize
> (DWORD
)BufferLength
)
178 /* Clear the aliases and return */
179 Hostent
->h_aliases
= NULL
;
183 /* Write the aliases, update the pointer */
184 ReturnedHostent
->h_aliases
= (PCHAR
*)p
;
185 p
= Buffer
+ CurrentSize
;
187 /* Find out how many names there are */
188 while (Hostent
->h_addr_list
[Names
])
190 /* Increase the alias count */
194 /* Add the names to the size, and validate it */
195 CurrentSize
+= (Names
+ 1) * sizeof(ULONG_PTR
);
196 if (CurrentSize
> (DWORD
)BufferLength
)
198 /* Clear the aliases and return */
199 Hostent
->h_addr_list
= NULL
;
203 /* Write the names, update the pointer */
204 ReturnedHostent
->h_addr_list
= (PCHAR
*)p
;
205 p
= Buffer
+ CurrentSize
;
207 /* Now add the names */
208 for (i
= 0; i
< Names
; i
++)
210 /* Update size and validate */
211 CurrentSize
+= Hostent
->h_length
;
212 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
214 /* Write pointer and copy */
215 ReturnedHostent
->h_addr_list
[i
] = p
;
216 CopyMemory(p
, Hostent
->h_addr_list
[i
], Hostent
->h_length
);
219 p
= Buffer
+ CurrentSize
;
222 /* Finalize the list */
223 ReturnedHostent
->h_addr_list
[i
] = NULL
;
225 /* Add the service name to the size, and validate it */
226 NameSize
= strlen(Hostent
->h_name
) + sizeof(CHAR
);
227 CurrentSize
+= NameSize
;
228 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
230 /* Write the service name and update the pointer */
231 ReturnedHostent
->h_name
= p
;
232 CopyMemory(p
, Hostent
->h_name
, NameSize
);
233 p
= Buffer
+ CurrentSize
;
235 /* Now add the aliases */
236 for (i
= 0; i
< Aliases
; i
++)
238 /* Update size and validate */
239 NameSize
= strlen(Hostent
->h_aliases
[i
]) + sizeof(CHAR
);
240 CurrentSize
+= NameSize
;
241 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
243 /* Write pointer and copy */
244 ReturnedHostent
->h_aliases
[i
] = p
;
245 CopyMemory(p
, Hostent
->h_aliases
[i
], NameSize
);
248 p
= Buffer
+ CurrentSize
;
251 /* Finalize the list and return */
252 ReturnedHostent
->h_aliases
[i
] = NULL
;
258 CopyServentToBuffer(IN PCHAR Buffer
,
262 SIZE_T BufferSize
, CurrentSize
, NameSize
;
266 PSERVENT ReturnedServent
= (PSERVENT
)Buffer
;
268 /* Determine the buffer size required */
269 BufferSize
= BytesInServent(Servent
);
271 /* Check which size to use */
272 if ((DWORD
)BufferLength
> BufferSize
)
274 /* Zero the buffer */
275 ZeroMemory(Buffer
, BufferSize
);
279 /* Zero the buffer */
280 ZeroMemory(Buffer
, BufferLength
);
283 /* Start with the raw servent */
284 CurrentSize
= sizeof(SERVENT
);
286 /* Return the size needed now */
287 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
289 /* Copy the servent and initialize it */
290 CopyMemory(p
, Servent
, sizeof(SERVENT
));
291 p
= Buffer
+ CurrentSize
;
292 ReturnedServent
->s_name
= NULL
;
293 ReturnedServent
->s_aliases
= NULL
;
294 ReturnedServent
->s_proto
= NULL
;
296 /* Find out how many aliases there are */
297 while (Servent
->s_aliases
[Aliases
])
299 /* Increase the alias count */
303 /* Add the aliases to the size, and validate it */
304 CurrentSize
+= (Aliases
+ 1) * sizeof(ULONG_PTR
);
305 if (CurrentSize
> (DWORD
)BufferLength
)
307 /* Clear the aliases and return */
308 Servent
->s_aliases
= NULL
;
312 /* Write the aliases, update the pointer */
313 ReturnedServent
->s_aliases
= (PCHAR
*)p
;
314 p
= Buffer
+ CurrentSize
;
316 /* Add the service name to the size, and validate it */
317 NameSize
= strlen(Servent
->s_name
) + sizeof(CHAR
);
318 CurrentSize
+= NameSize
;
319 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
321 /* Write the service name and update the pointer */
322 ReturnedServent
->s_name
= p
;
323 CopyMemory(p
, Servent
->s_name
, NameSize
);
324 p
= Buffer
+ CurrentSize
;
326 /* Now add the aliases */
327 for (i
= 0; i
< Aliases
; i
++)
329 /* Update size and validate */
330 NameSize
= strlen(Servent
->s_aliases
[i
]) + sizeof(CHAR
);
331 CurrentSize
+= NameSize
;
332 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
334 /* Write pointer and copy */
335 ReturnedServent
->s_aliases
[i
] = p
;
336 CopyMemory(p
, Servent
->s_aliases
[i
], NameSize
);
339 p
= Buffer
+ CurrentSize
;
342 /* Finalize the list and return */
343 ReturnedServent
->s_aliases
[i
] = NULL
;
349 CopyProtoentToBuffer(IN PCHAR Buffer
,
351 IN PPROTOENT Protoent
)
353 SIZE_T BufferSize
, CurrentSize
, NameSize
;
357 PPROTOENT ReturnedProtoent
= (PPROTOENT
)Buffer
;
359 /* Determine the buffer size required */
360 BufferSize
= BytesInProtoent(Protoent
);
362 /* Check which size to use */
363 if ((DWORD
)BufferLength
> BufferSize
)
365 /* Zero the buffer */
366 ZeroMemory(Buffer
, BufferSize
);
370 /* Zero the buffer */
371 ZeroMemory(Buffer
, BufferLength
);
374 /* Start with the raw servent */
375 CurrentSize
= sizeof(PROTOENT
);
377 /* Return the size needed now */
378 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
380 /* Copy the servent and initialize it */
381 CopyMemory(p
, Protoent
, sizeof(PROTOENT
));
382 p
= Buffer
+ CurrentSize
;
383 ReturnedProtoent
->p_name
= NULL
;
384 ReturnedProtoent
->p_aliases
= NULL
;
386 /* Find out how many aliases there are */
387 while (Protoent
->p_aliases
[Aliases
])
389 /* Increase the alias count */
393 /* Add the aliases to the size, and validate it */
394 CurrentSize
+= (Aliases
+ 1) * sizeof(ULONG_PTR
);
395 if (CurrentSize
> (DWORD
)BufferLength
)
397 /* Clear the aliases and return */
398 Protoent
->p_aliases
= NULL
;
402 /* Write the aliases, update the pointer */
403 ReturnedProtoent
->p_aliases
= (PCHAR
*)p
;
404 p
= Buffer
+ CurrentSize
;
406 /* Add the service name to the size, and validate it */
407 NameSize
= strlen(Protoent
->p_name
) + sizeof(CHAR
);
408 CurrentSize
+= NameSize
;
409 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
411 /* Write the service name and update the pointer */
412 ReturnedProtoent
->p_name
= p
;
413 CopyMemory(p
, Protoent
->p_name
, NameSize
);
414 p
= Buffer
+ CurrentSize
;
416 /* Now add the aliases */
417 for (i
= 0; i
< Aliases
; i
++)
419 /* Update size and validate */
420 NameSize
= strlen(Protoent
->p_aliases
[i
]) + sizeof(CHAR
);
421 CurrentSize
+= NameSize
;
422 if (CurrentSize
> (DWORD
)BufferLength
) return BufferSize
;
424 /* Write pointer and copy */
425 ReturnedProtoent
->p_aliases
[i
] = p
;
426 CopyMemory(p
, Protoent
->p_aliases
[i
], NameSize
);
429 p
= Buffer
+ CurrentSize
;
432 /* Finalize the list and return */
433 ReturnedProtoent
->p_aliases
[i
] = NULL
;
439 WsAsyncAllocateBlock(IN SIZE_T ExtraLength
)
441 PWSASYNCBLOCK AsyncBlock
;
443 /* Add the size of the block */
444 ExtraLength
+= sizeof(WSASYNCBLOCK
);
447 AsyncBlock
= HeapAlloc(WsSockHeap
, 0, ExtraLength
);
449 /* Get a handle to it */
450 AsyncBlock
->TaskHandle
= UlongToPtr(InterlockedIncrement(&WsAsyncTaskHandle
));
458 WsAsyncThreadBlockingHook(VOID
)
460 /* Check if this task is being cancelled */
461 if (WsAsyncCurrentTaskHandle
== WsAsyncCancelledTaskHandle
)
463 /* Cancel the blocking call so we can get back */
464 WSACancelBlockingCall();
467 /* Return to system */
473 WsAsyncFreeBlock(IN PWSASYNCBLOCK AsyncBlock
)
476 HeapFree(WsSockHeap
, 0, AsyncBlock
);
481 WsAsyncGetServ(IN HANDLE TaskHandle
,
486 IN CHAR FAR
*Protocol
,
491 SIZE_T BufferSize
= 0;
495 /* Check the operaiton */
496 if (Operation
== WsAsyncGetServByName
)
499 Servent
= getservbyname(ByWhat
, Protocol
);
504 Servent
= getservbyport(PtrToUlong(ByWhat
), Protocol
);
507 /* Make sure we got one */
508 if (!Servent
) ErrorCode
= GetLastError();
510 /* Acquire the lock */
513 /* Check if this task got cancelled */
514 if (TaskHandle
== WsAsyncCancelledTaskHandle
)
521 /* If we got a Servent back, copy it */
524 /* Copy it into the buffer */
525 BufferSize
= CopyServentToBuffer(Buffer
, BufferLength
, Servent
);
527 /* Check if we had enough space */
528 if (BufferSize
> (DWORD
)BufferLength
)
531 ErrorCode
= WSAENOBUFS
;
536 ErrorCode
= NO_ERROR
;
540 /* Not processing anyomre */
541 WsAsyncCurrentTaskHandle
= NULL
;
543 /* Release the lock */
546 /* Make the messed-up lParam reply */
547 lParam
= WSAMAKEASYNCREPLY(BufferSize
, ErrorCode
);
549 /* Sent it through the Upcall API */
550 WPUPostMessage(hWnd
, wMsg
, (WPARAM
)TaskHandle
, lParam
);
555 WsAsyncGetProto(IN HANDLE TaskHandle
,
564 SIZE_T BufferSize
= 0;
568 /* Check the operaiton */
569 if (Operation
== WsAsyncGetProtoByName
)
572 Protoent
= getprotobyname(ByWhat
);
577 Protoent
= getprotobynumber(PtrToUlong(ByWhat
));
580 /* Make sure we got one */
581 if (!Protoent
) ErrorCode
= GetLastError();
583 /* Acquire the lock */
586 /* Check if this task got cancelled */
587 if (TaskHandle
== WsAsyncCancelledTaskHandle
)
594 /* If we got a Servent back, copy it */
597 /* Copy it into the buffer */
598 BufferSize
= CopyProtoentToBuffer(Buffer
, BufferLength
, Protoent
);
600 /* Check if we had enough space */
601 if (BufferSize
> (DWORD
)BufferLength
)
604 ErrorCode
= WSAENOBUFS
;
609 ErrorCode
= NO_ERROR
;
613 /* Not processing anyomre */
614 WsAsyncCurrentTaskHandle
= NULL
;
616 /* Release the lock */
619 /* Make the messed-up lParam reply */
620 lParam
= WSAMAKEASYNCREPLY(BufferSize
, ErrorCode
);
622 /* Sent it through the Upcall API */
623 WPUPostMessage(hWnd
, wMsg
, (WPARAM
)TaskHandle
, lParam
);
628 WsAsyncGetHost(IN HANDLE TaskHandle
,
639 SIZE_T BufferSize
= 0;
643 /* Check the operaiton */
644 if (Operation
== WsAsyncGetHostByAddr
)
647 Hostent
= gethostbyaddr(ByWhat
, Length
, Type
);
652 Hostent
= gethostbyname(ByWhat
);
655 /* Make sure we got one */
656 if (!Hostent
) ErrorCode
= GetLastError();
658 /* Acquire the lock */
661 /* Check if this task got cancelled */
662 if (TaskHandle
== WsAsyncCancelledTaskHandle
)
669 /* If we got a Servent back, copy it */
672 /* Copy it into the buffer */
673 BufferSize
= CopyHostentToBuffer(Buffer
, BufferLength
, Hostent
);
675 /* Check if we had enough space */
676 if (BufferSize
> (DWORD
)BufferLength
)
679 ErrorCode
= WSAENOBUFS
;
684 ErrorCode
= NO_ERROR
;
688 /* Not processing anyomre */
689 WsAsyncCurrentTaskHandle
= NULL
;
691 /* Release the lock */
694 /* Make the messed-up lParam reply */
695 lParam
= WSAMAKEASYNCREPLY(BufferSize
, ErrorCode
);
697 /* Sent it through the Upcall API */
698 WPUPostMessage(hWnd
, wMsg
, (WPARAM
)TaskHandle
, lParam
);
703 WsAsyncThread(IN PWSASYNCCONTEXT Context
)
705 PWSASYNCBLOCK AsyncBlock
;
707 HANDLE AsyncEvent
= Context
->AsyncEvent
;
708 PLIST_ENTRY ListHead
= &Context
->AsyncQueue
;
710 /* Set the blocking hook */
711 WSASetBlockingHook((FARPROC
)WsAsyncThreadBlockingHook
);
716 /* Wait for the event */
717 WaitForSingleObject(AsyncEvent
, INFINITE
);
722 /* Process the queue */
723 while (ListHead
->Flink
!= ListHead
)
725 /* Remove this entry and get the async block */
726 Entry
= RemoveHeadList(ListHead
);
727 AsyncBlock
= CONTAINING_RECORD(Entry
, WSASYNCBLOCK
, AsyncQueue
);
729 /* Save the current task handle */
730 WsAsyncCurrentTaskHandle
= AsyncBlock
->TaskHandle
;
732 /* Release the lock */
735 /* Check which operation to do */
736 switch (AsyncBlock
->Operation
)
739 case WsAsyncGetHostByAddr
: case WsAsyncGetHostByName
:
741 /* Call the handler */
742 WsAsyncGetHost(AsyncBlock
->TaskHandle
,
743 AsyncBlock
->Operation
,
744 AsyncBlock
->GetHost
.hWnd
,
745 AsyncBlock
->GetHost
.wMsg
,
746 AsyncBlock
->GetHost
.ByWhat
,
747 AsyncBlock
->GetHost
.Length
,
748 AsyncBlock
->GetHost
.Type
,
749 AsyncBlock
->GetHost
.Buffer
,
750 AsyncBlock
->GetHost
.BufferLength
);
754 case WsAsyncGetProtoByNumber
: case WsAsyncGetProtoByName
:
756 /* Call the handler */
757 WsAsyncGetProto(AsyncBlock
->TaskHandle
,
758 AsyncBlock
->Operation
,
759 AsyncBlock
->GetProto
.hWnd
,
760 AsyncBlock
->GetProto
.wMsg
,
761 AsyncBlock
->GetHost
.ByWhat
,
762 AsyncBlock
->GetProto
.Buffer
,
763 AsyncBlock
->GetProto
.BufferLength
);
767 case WsAsyncGetServByPort
: case WsAsyncGetServByName
:
769 /* Call the handler */
770 WsAsyncGetServ(AsyncBlock
->TaskHandle
,
771 AsyncBlock
->Operation
,
772 AsyncBlock
->GetServ
.hWnd
,
773 AsyncBlock
->GetServ
.wMsg
,
774 AsyncBlock
->GetServ
.ByWhat
,
775 AsyncBlock
->GetServ
.Protocol
,
776 AsyncBlock
->GetServ
.Buffer
,
777 AsyncBlock
->GetServ
.BufferLength
);
781 case WsAsyncTerminate
:
783 /* Clean up the extra reference */
786 /* Free the context block */
787 WsAsyncFreeBlock(AsyncBlock
);
789 /* Acquire the lock */
792 /* Loop the queue and flush it */
793 while (!IsListEmpty(ListHead
))
795 Entry
= RemoveHeadList(ListHead
);
796 AsyncBlock
= CONTAINING_RECORD(Entry
,
799 WsAsyncFreeBlock(AsyncBlock
);
805 /* Close the event, free the Context */
806 CloseHandle(AsyncEvent
);
807 HeapFree(WsSockHeap
, 0, Context
);
809 /* Remove the extra DLL reference and kill us */
810 FreeLibraryAndExitThread(WsAsyncDllHandle
, 0);
816 /* Done processing */
817 WsAsyncCurrentTaskHandle
= NULL
;
819 /* Free this block, get lock and reloop */
820 WsAsyncFreeBlock(AsyncBlock
);
824 /* Release the lock */
831 WsAsyncCheckAndInitThread(VOID
)
835 PWSASYNCCONTEXT Context
= NULL
;
838 /* Make sure we're not initialized */
839 if (WsAsyncThreadInitialized
) return TRUE
;
841 /* Acquire the lock */
844 /* Make sure we're not initialized */
845 if (!WsAsyncThreadInitialized
)
847 /* Initialize Thread Context */
848 Context
= HeapAlloc(WsSockHeap
, 0, sizeof(*Context
));
850 /* Initialize the Queue and event */
851 WsAsyncQueue
= &Context
->AsyncQueue
;
852 InitializeListHead(WsAsyncQueue
);
853 Context
->AsyncEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
854 WsAsyncEvent
= Context
->AsyncEvent
;
856 /* Prevent us from ever being killed while running */
857 WSAStartup(MAKEWORD(2,2), &WsaData
);
859 /* Create the thread */
860 ThreadHandle
= CreateThread(NULL
,
862 (LPTHREAD_START_ROUTINE
)WsAsyncThread
,
867 /* Close the handle and set init */
868 CloseHandle(ThreadHandle
);
869 WsAsyncThreadInitialized
= TRUE
;
872 /* Release the lock */
874 return WsAsyncThreadInitialized
;
879 WsAsyncTerminateThread(VOID
)
881 PWSASYNCBLOCK AsyncBlock
;
883 /* Make sure we're initialized */
884 if (!WsAsyncThreadInitialized
) return;
886 /* Allocate a block */
887 AsyncBlock
= WsAsyncAllocateBlock(0);
889 /* Initialize it for termination */
890 AsyncBlock
->Operation
= WsAsyncTerminate
;
892 /* Queue the request and return */
893 WsAsyncQueueRequest(AsyncBlock
);
894 WsAsyncThreadInitialized
= FALSE
;
899 WsAsyncQueueRequest(IN PWSASYNCBLOCK AsyncBlock
)
904 /* Insert it into the queue */
905 InsertTailList(WsAsyncQueue
, &AsyncBlock
->AsyncQueue
);
907 /* Wake up the thread */
908 SetEvent(WsAsyncEvent
);
910 /* Release lock and return */
916 WsAsyncCancelRequest(IN HANDLE TaskHandle
)
919 PWSASYNCBLOCK AsyncBlock
;
921 /* Make sure we're initialized */
922 if (!WsAsyncThreadInitialized
) return WSAEINVAL
;
924 /* Acquire the lock */
927 /* Check if we're cancelling the current task */
928 if (TaskHandle
== WsAsyncCurrentTaskHandle
)
930 /* Mark us as cancelled, the async thread will see this later */
931 WsAsyncCancelledTaskHandle
= TaskHandle
;
933 /* Release lock and return */
939 Entry
= WsAsyncQueue
->Flink
;
940 while (Entry
!= WsAsyncQueue
)
942 /* Get the Async Block */
943 AsyncBlock
= CONTAINING_RECORD(Entry
, WSASYNCBLOCK
, AsyncQueue
);
945 /* Check if this is the one */
946 if (TaskHandle
== AsyncBlock
->TaskHandle
)
948 /* It is, remove it */
949 RemoveEntryList(Entry
);
951 /* Release the lock, free the block, and return */
953 WsAsyncFreeBlock(AsyncBlock
);
957 /* Move to the next entry */
958 Entry
= Entry
->Flink
;
961 /* Nothing found, fail */