2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 DLL
4 * FILE: include/ws2_32.h
5 * PURPOSE: WinSock 2 DLL header
8 /* INCLUDES ******************************************************************/
14 /* DATA **********************************************************************/
16 CRITICAL_SECTION WshHandleTableLock
;
18 DWORD gdwSpinCount
= 0;
19 DWORD gHandleToIndexMask
;
21 CONST DWORD SockPrimes
[] =
23 31, 61, 127, 257, 521, 1031, 2053,
24 4099, 8191, 16381, 32749, 65537, 131071, 261983,
28 typedef volatile LONG VLONG
;
29 typedef VLONG
*PVLONG
;
31 /* DEFINES *******************************************************************/
33 /* Yes, we "abuse" the lower bits */
34 #define WSH_SEARCH_TABLE_FROM_HANDLE(h, t) \
35 (&t->SearchTables[(((ULONG_PTR)h >> 2) & t->Mask)])
37 #define WSH_HASH_FROM_HANDLE(h, hs) \
38 (hs->Handles[((ULONG_PTR)h % hs->Size)])
40 #define AcquireWriteLock(t) \
41 EnterCriticalSection(&t->Lock);
43 #define ReleaseWriteLock(t) \
44 LeaveCriticalSection(&t->Lock);
46 /* FUNCTIONS *****************************************************************/
50 AcquireReadLock(IN PWAH_SEARCH_TABLE Table
,
55 /* Start acquire loop */
58 /* Write and save count value */
59 *Count
= Table
->CurrentCount
;
62 /* Check if it's valid and try to increment it */
63 if ((OldCount
> 0) && (InterlockedCompareExchange(*Count
,
65 OldCount
) == OldCount
))
67 /* Everything went OK */
75 ReleaseReadLock(IN PWAH_SEARCH_TABLE Table
,
78 /* Decrement the count. If we went below 0, someone is waiting... */
79 if (InterlockedDecrement(Count
) < 0)
81 /* We use pulse since this is a shared event */
82 PulseEvent(ghWriterEvent
);
88 DoWaitForReaders(IN PWAH_SEARCH_TABLE Table
,
93 /* Do a context switch */
96 /* Check if the counter is above one */
100 * This shouldn't happen unless priorities are messed up. Do a wait so
101 * that the threads with lower priority will get their chance now.
105 /* We don't even have an event! Allocate one manually... */
106 EventHandle
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
109 /* Save the event handle atomically */
110 if ((InterlockedCompareExchangePointer((PVOID
*)&ghWriterEvent
,
114 /* Someone beat us to it, close ours */
115 CloseHandle(EventHandle
);
120 /* Things couldn't get worse for us. Do a last-resort hack */
121 while (*Counter
> 0) Sleep(10);
126 * Our event is ready. Tell the others to signal us by making sure
127 * that the last counter will be -1, notifying the last thread of our
130 if (InterlockedDecrement(Counter
) >= 0)
135 /* Wait in tiny bursts, so we can catch the PulseEvent */
136 WaitForSingleObject(ghWriterEvent
, 10);
137 } while (*Counter
>= 0);
144 TryWaitForReaders(IN PWAH_SEARCH_TABLE Table
)
146 PVLONG OldCount
= Table
->CurrentCount
;
149 /* See which counter is being used */
150 if (OldCount
== &Table
->Count1
)
152 /* Use counter 2 now */
154 Table
->CurrentCount
= &Table
->Count2
;
158 /* Use counter 1 now */
160 Table
->CurrentCount
= &Table
->Count1
;
163 /* Decrease the old count to block new readers */
164 if (InterlockedDecrement(OldCount
) > 0)
166 /* On an MP machine, spin a bit first */
167 if (Table
->SpinCount
)
169 /* Get the spincount and loop it */
170 SpinCount
= Table
->SpinCount
;
171 while (*OldCount
> 0)
173 /* Check if the spin failed */
174 if (--SpinCount
<= 0) break;
178 /* Check one last time if someone is still active */
181 /* Yep, we'll have to do a blocking (slow) wait */
182 DoWaitForReaders(Table
, OldCount
);
189 WahCreateHandleContextTable(OUT PWAH_HANDLE_TABLE
*Table
)
192 PWAH_HANDLE_TABLE LocalTable
;
195 /* Enter the prolog, make sure we're initialized */
196 ErrorCode
= WS2HELP_PROLOG();
197 if (ErrorCode
!= ERROR_SUCCESS
) return ErrorCode
;
202 /* Allocate enough tables */
203 LocalTable
= HeapAlloc(GlobalHeap
,
205 FIELD_OFFSET(WSH_HANDLE_TABLE
,
206 SearchTables
[gHandleToIndexMask
+ 1]));
208 /* Make sure it was allocated */
209 if (!LocalTable
) return WSA_NOT_ENOUGH_MEMORY
;
211 /* Set the mask for the table */
212 LocalTable
->Mask
= gHandleToIndexMask
;
214 /* Now initialize every table */
215 for (i
= 0; i
<= gHandleToIndexMask
; i
++)
217 /* No hash table yet */
218 LocalTable
->SearchTables
[i
].HashTable
= NULL
;
220 /* Set the current count */
221 LocalTable
->SearchTables
[i
].CurrentCount
= &LocalTable
->SearchTables
[i
].Count1
;
223 /* Initialize the counts */
224 LocalTable
->SearchTables
[i
].Count1
= 1;
225 LocalTable
->SearchTables
[i
].Count2
= 0;
227 /* Set expanding state and spin count */
228 LocalTable
->SearchTables
[i
].Expanding
= FALSE
;
229 LocalTable
->SearchTables
[i
].SpinCount
= gdwSpinCount
;
231 /* Initialize the lock */
232 (VOID
)InitializeCriticalSectionAndSpinCount(&LocalTable
->
233 SearchTables
[i
].Lock
,
241 return ERROR_SUCCESS
;
246 WahDestroyHandleContextTable(IN PWAH_HANDLE_TABLE Table
)
250 /* Make sure the table is valid */
254 return ERROR_INVALID_PARAMETER
;
257 /* Loop each search table */
258 for (i
= 0; i
<= Table
->Mask
; i
++)
260 /* Check if there's a table here */
261 if (Table
->SearchTables
[i
].HashTable
)
264 HeapFree(GlobalHeap
, 0, Table
->SearchTables
[i
].HashTable
);
267 /* Delete the lock */
268 DeleteCriticalSection(&Table
->SearchTables
[i
].Lock
);
271 /* Delete the table */
272 HeapFree(GlobalHeap
, 0, Table
);
275 return ERROR_SUCCESS
;
280 WahEnumerateHandleContexts(IN PWAH_HANDLE_TABLE Table
,
281 IN PWAH_HANDLE_ENUMERATE_PROC Callback
,
285 PWAH_SEARCH_TABLE SearchTable
;
286 PWAH_HASH_TABLE HashTable
;
291 for (i
= 0; i
<= Table
->Mask
; i
++)
293 /* Get the Search table */
294 SearchTable
= &Table
->SearchTables
[i
];
297 AcquireWriteLock(SearchTable
);
299 /* Mark us as expanding and wait for everyone */
300 SearchTable
->Expanding
= TRUE
;
301 TryWaitForReaders(SearchTable
);
303 /* Get the hash table */
304 HashTable
= SearchTable
->HashTable
;
306 /* Make sure it exists */
309 /* Loop every handle in it */
310 for (j
= 0; j
< HashTable
->Size
; j
++)
312 /* Get this handle */
313 Handle
= HashTable
->Handles
[j
];
314 if (!Handle
) continue;
316 /* Call the callback proc */
317 GoOn
= Callback(Context
, Handle
);
322 /* Disable the expansion bit and release the lock */
323 SearchTable
->Expanding
= FALSE
;
324 ReleaseWriteLock(SearchTable
);
326 /* Check again if we should leave */
336 WahInsertHandleContext(IN PWAH_HANDLE_TABLE Table
,
337 IN PWAH_HANDLE Handle
)
339 PWAH_HANDLE
*HashHandle
, OldHandle
;
341 PWAH_HASH_TABLE HashTable
, NewHashTable
;
342 DWORD HandleCount
, i
;
343 PWAH_SEARCH_TABLE SearchTable
;
345 /* Get the current Search Table */
346 SearchTable
= WSH_SEARCH_TABLE_FROM_HANDLE(Handle
->Handle
, Table
);
351 /* Get reader lock */
352 AcquireReadLock(SearchTable
, &Count
);
354 /* Get the hash table */
355 HashTable
= SearchTable
->HashTable
;
357 /* Make sure we are not expanding, and that the table is there */
358 if (!(SearchTable
->Expanding
) && (HashTable
))
360 /* Get the hash handle */
361 HashHandle
= &WSH_HASH_FROM_HANDLE(Handle
->Handle
, HashTable
);
364 if (InterlockedCompareExchangePointer((PVOID
*)HashHandle
,
368 /* Success, release the reader lock */
369 ReleaseReadLock(SearchTable
, Count
);
371 /* Save old handle */
377 /* Release the read lock since we're done with it now */
378 ReleaseReadLock(SearchTable
, Count
);
380 /* We need the writer lock to expand/create the table */
381 AcquireWriteLock(SearchTable
);
383 /* Mark the table in use */
384 SearchTable
->Expanding
= TRUE
;
386 /* Wait for all the readers to finish */
387 TryWaitForReaders(SearchTable
);
392 /* Get the hash table again */
393 HashTable
= SearchTable
->HashTable
;
395 /* Check if exists now */
398 /* It does! Do what we wanted to do earlier. Get the hash... */
399 HashHandle
= &WSH_HASH_FROM_HANDLE(Handle
->Handle
, HashTable
);
401 /* Check if it doesn't exist */
404 /* Write it (no need for interlock, we have the RW lock) */
406 *HashHandle
= Handle
;
409 else if ((*HashHandle
)->Handle
== Handle
->Handle
)
411 /* Handle matches, write it (see comment above) */
412 OldHandle
= *HashHandle
;
413 *HashHandle
= Handle
;
417 /* No go, we need to expand the table. Remember the size now */
418 HandleCount
= HashTable
->Size
;
422 /* Table is empty, we have to create it */
427 /* Find a free prime */
428 for (i
= 0; HandleCount
>= SockPrimes
[i
]; i
++);
430 /* Check if we found one */
431 if (SockPrimes
[i
] != 0xFFFFFFFF)
434 HandleCount
= SockPrimes
[i
];
438 /* No primes left. Table is quite large, so simply double it */
442 /* Allocate the table */
443 NewHashTable
= HeapAlloc(GlobalHeap
,
445 FIELD_OFFSET(WSH_HASH_TABLE
,
446 Handles
[HandleCount
]));
448 /* Hopefully we have one now */
452 NewHashTable
->Size
= HandleCount
;
455 RtlZeroMemory(NewHashTable
->Handles
, HandleCount
* sizeof(PVOID
));
457 /* Insert us first */
458 WSH_HASH_FROM_HANDLE(Handle
->Handle
, NewHashTable
) = Handle
;
460 /* Now check if our old table had entries in it */
463 /* We need to move them */
464 for (i
= 0; i
< HashTable
->Size
; i
++)
466 /* Make sure the hash handle exists */
467 if (HashTable
->Handles
[i
])
470 HashHandle
= &WSH_HASH_FROM_HANDLE(HashTable
->
474 /* Check if it has a value */
477 /* It's empty, so just write the handle */
478 *HashHandle
= HashTable
->Handles
[i
];
482 /* Not empty :/... that implies a collision */
483 HeapFree(GlobalHeap
, 0, NewHashTable
);
489 /* Write the new hash table */
490 SearchTable
->HashTable
= NewHashTable
;
492 /* Wait for everyone to be done with it, then free it */
493 TryWaitForReaders(SearchTable
);
494 HeapFree(GlobalHeap
, 0, HashTable
);
498 /* It was empty, nothing to worry about */
499 SearchTable
->HashTable
= NewHashTable
;
502 /* Save the old handle */
507 /* There was no old handle */
512 /* Mark us as free, and release the write lock */
513 SearchTable
->Expanding
= FALSE
;
514 ReleaseWriteLock(SearchTable
);
518 /* Return the old handle */
524 WahReferenceContextByHandle(IN PWAH_HANDLE_TABLE Table
,
527 PWAH_HANDLE HashHandle
;
528 PWAH_SEARCH_TABLE SearchTable
;
529 PWAH_HASH_TABLE HashTable
;
532 /* Get the current Search Table */
533 SearchTable
= WSH_SEARCH_TABLE_FROM_HANDLE(Handle
, Table
);
536 AcquireReadLock(SearchTable
, &Count
);
538 /* Get the hash table and handle */
539 HashTable
= SearchTable
->HashTable
;
541 /* Check if it's valid, and if it's the one we want */
543 (HashHandle
= WSH_HASH_FROM_HANDLE(Handle
, HashTable
)) &&
544 (HashHandle
->Handle
== Handle
))
546 /* Reference the handle */
547 InterlockedIncrement(&HashHandle
->RefCount
);
555 /* Release the lock */
556 ReleaseReadLock(SearchTable
, Count
);
564 WahRemoveHandleContext(IN PWAH_HANDLE_TABLE Table
,
565 IN PWAH_HANDLE Handle
)
567 PWAH_HANDLE
*HashHandle
;
568 PWAH_SEARCH_TABLE SearchTable
;
569 PWAH_HASH_TABLE HashTable
;
570 DWORD ErrorCode
= ERROR_SUCCESS
;
572 /* Get the current Search Table */
573 SearchTable
= WSH_SEARCH_TABLE_FROM_HANDLE(Handle
->Handle
, Table
);
576 AcquireWriteLock(SearchTable
);
578 /* Get the hash table and handle */
579 HashTable
= SearchTable
->HashTable
;
580 HashHandle
= &WSH_HASH_FROM_HANDLE(Handle
->Handle
, HashTable
);
582 /* Make sure we have a handle, and write the new pointer */
583 if (HashHandle
&& (InterlockedCompareExchangePointer((PVOID
*)HashHandle
,
587 /* Wait for everyone to be done with it */
588 TryWaitForReaders(SearchTable
);
593 ErrorCode
= ERROR_INVALID_PARAMETER
;
596 /* Release the lock */
597 ReleaseWriteLock(SearchTable
);