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 ******************************************************************/
12 /* DATA **********************************************************************/
14 CRITICAL_SECTION WshHandleTableLock
;
16 DWORD gdwSpinCount
= 0;
17 DWORD gHandleToIndexMask
;
19 CONST DWORD SockPrimes
[] =
21 31, 61, 127, 257, 521, 1031, 2053,
22 4099, 8191, 16381, 32749, 65537, 131071, 261983,
26 typedef volatile LONG VLONG
;
27 typedef VLONG
*PVLONG
;
29 /* DEFINES *******************************************************************/
31 /* Yes, we "abuse" the lower bits */
32 #define WSH_SEARCH_TABLE_FROM_HANDLE(h, t) \
33 (&t->SearchTables[(((ULONG_PTR)h >> 2) & t->Mask)])
35 #define WSH_HASH_FROM_HANDLE(h, hs) \
36 (hs->Handles[((ULONG_PTR)h % hs->Size)])
38 #define AcquireWriteLock(t) \
39 EnterCriticalSection(&t->Lock);
41 #define ReleaseWriteLock(t) \
42 LeaveCriticalSection(&t->Lock);
44 /* FUNCTIONS *****************************************************************/
48 AcquireReadLock(IN PWAH_SEARCH_TABLE Table
,
53 /* Start acquire loop */
56 /* Write and save count value */
57 *Count
= Table
->CurrentCount
;
60 /* Check if it's valid and try to increment it */
61 if ((OldCount
> 0) && (InterlockedCompareExchange(*Count
,
63 OldCount
) == OldCount
))
65 /* Everything went OK */
73 ReleaseReadLock(IN PWAH_SEARCH_TABLE Table
,
76 /* Decrement the count. If we went below 0, someone is waiting... */
77 if (InterlockedDecrement(Count
) < 0)
79 /* We use pulse since this is a shared event */
80 PulseEvent(ghWriterEvent
);
86 DoWaitForReaders(IN PWAH_SEARCH_TABLE Table
,
91 /* Do a context switch */
94 /* Check if the counter is above one */
98 * This shouldn't happen unless priorities are messed up. Do a wait so
99 * that the threads with lower priority will get their chance now.
103 /* We don't even have an event! Allocate one manually... */
104 EventHandle
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
107 /* Save the event handle atomically */
108 if ((InterlockedCompareExchangePointer((PVOID
*)&ghWriterEvent
,
112 /* Someone beat us to it, close ours */
113 CloseHandle(EventHandle
);
118 /* Things couldn't get worse for us. Do a last-resort hack */
119 while (*Counter
> 0) Sleep(10);
124 * Our event is ready. Tell the others to signal us by making sure
125 * that the last counter will be -1, notifying the last thread of our
128 if (InterlockedDecrement(Counter
) >= 0)
133 /* Wait in tiny bursts, so we can catch the PulseEvent */
134 WaitForSingleObject(ghWriterEvent
, 10);
135 } while (*Counter
>= 0);
142 TryWaitForReaders(IN PWAH_SEARCH_TABLE Table
)
144 PVLONG OldCount
= Table
->CurrentCount
;
147 /* See which counter is being used */
148 if (OldCount
== &Table
->Count1
)
150 /* Use counter 2 now */
152 Table
->CurrentCount
= &Table
->Count2
;
156 /* Use counter 1 now */
158 Table
->CurrentCount
= &Table
->Count1
;
161 /* Decrease the old count to block new readers */
162 if (InterlockedDecrement(OldCount
) > 0)
164 /* On an MP machine, spin a bit first */
165 if (Table
->SpinCount
)
167 /* Get the spincount and loop it */
168 SpinCount
= Table
->SpinCount
;
169 while (*OldCount
> 0)
171 /* Check if the spin failed */
172 if (--SpinCount
<= 0) break;
176 /* Check one last time if someone is still active */
179 /* Yep, we'll have to do a blocking (slow) wait */
180 DoWaitForReaders(Table
, OldCount
);
187 WahCreateHandleContextTable(OUT PWAH_HANDLE_TABLE
*Table
)
190 PWAH_HANDLE_TABLE LocalTable
;
193 /* Enter the prolog, make sure we're initialized */
194 ErrorCode
= WS2HELP_PROLOG();
195 if (ErrorCode
!= ERROR_SUCCESS
) return ErrorCode
;
200 /* Allocate enough tables */
201 LocalTable
= HeapAlloc(GlobalHeap
,
203 FIELD_OFFSET(WSH_HANDLE_TABLE
,
204 SearchTables
[gHandleToIndexMask
+ 1]));
206 /* Make sure it was allocated */
207 if (!LocalTable
) return WSA_NOT_ENOUGH_MEMORY
;
209 /* Set the mask for the table */
210 LocalTable
->Mask
= gHandleToIndexMask
;
212 /* Now initialize every table */
213 for (i
= 0; i
<= gHandleToIndexMask
; i
++)
215 /* No hash table yet */
216 LocalTable
->SearchTables
[i
].HashTable
= NULL
;
218 /* Set the current count */
219 LocalTable
->SearchTables
[i
].CurrentCount
= &LocalTable
->SearchTables
[i
].Count1
;
221 /* Initialize the counts */
222 LocalTable
->SearchTables
[i
].Count1
= 1;
223 LocalTable
->SearchTables
[i
].Count2
= 0;
225 /* Set expanding state and spin count */
226 LocalTable
->SearchTables
[i
].Expanding
= FALSE
;
227 LocalTable
->SearchTables
[i
].SpinCount
= gdwSpinCount
;
229 /* Initialize the lock */
230 (VOID
)InitializeCriticalSectionAndSpinCount(&LocalTable
->
231 SearchTables
[i
].Lock
,
239 return ERROR_SUCCESS
;
244 WahDestroyHandleContextTable(IN PWAH_HANDLE_TABLE Table
)
248 /* Make sure the table is valid */
252 return ERROR_INVALID_PARAMETER
;
255 /* Loop each search table */
256 for (i
= 0; i
<= Table
->Mask
; i
++)
258 /* Check if there's a table here */
259 if (Table
->SearchTables
[i
].HashTable
)
262 HeapFree(GlobalHeap
, 0, Table
->SearchTables
[i
].HashTable
);
265 /* Delete the lock */
266 DeleteCriticalSection(&Table
->SearchTables
[i
].Lock
);
269 /* Delete the table */
270 HeapFree(GlobalHeap
, 0, Table
);
273 return ERROR_SUCCESS
;
278 WahEnumerateHandleContexts(IN PWAH_HANDLE_TABLE Table
,
279 IN PWAH_HANDLE_ENUMERATE_PROC Callback
,
283 PWAH_SEARCH_TABLE SearchTable
;
284 PWAH_HASH_TABLE HashTable
;
289 for (i
= 0; i
<= Table
->Mask
; i
++)
291 /* Get the Search table */
292 SearchTable
= &Table
->SearchTables
[i
];
295 AcquireWriteLock(SearchTable
);
297 /* Mark us as expanding and wait for everyone */
298 SearchTable
->Expanding
= TRUE
;
299 TryWaitForReaders(SearchTable
);
301 /* Get the hash table */
302 HashTable
= SearchTable
->HashTable
;
304 /* Make sure it exists */
307 /* Loop every handle in it */
308 for (j
= 0; j
< HashTable
->Size
; j
++)
310 /* Get this handle */
311 Handle
= HashTable
->Handles
[j
];
312 if (!Handle
) continue;
314 /* Call the callback proc */
315 GoOn
= Callback(Context
, Handle
);
320 /* Disable the expansion bit and release the lock */
321 SearchTable
->Expanding
= FALSE
;
322 ReleaseWriteLock(SearchTable
);
324 /* Check again if we should leave */
334 WahInsertHandleContext(IN PWAH_HANDLE_TABLE Table
,
335 IN PWAH_HANDLE Handle
)
337 PWAH_HANDLE
*HashHandle
, OldHandle
;
339 PWAH_HASH_TABLE HashTable
, NewHashTable
;
340 DWORD HandleCount
, i
;
341 PWAH_SEARCH_TABLE SearchTable
;
343 /* Get the current Search Table */
344 SearchTable
= WSH_SEARCH_TABLE_FROM_HANDLE(Handle
->Handle
, Table
);
349 /* Get reader lock */
350 AcquireReadLock(SearchTable
, &Count
);
352 /* Get the hash table */
353 HashTable
= SearchTable
->HashTable
;
355 /* Make sure we are not expanding, and that the table is there */
356 if (!(SearchTable
->Expanding
) && (HashTable
))
358 /* Get the hash handle */
359 HashHandle
= &WSH_HASH_FROM_HANDLE(Handle
->Handle
, HashTable
);
362 if (InterlockedCompareExchangePointer((PVOID
*)HashHandle
,
366 /* Success, release the reader lock */
367 ReleaseReadLock(SearchTable
, Count
);
369 /* Save old handle */
375 /* Release the read lock since we're done with it now */
376 ReleaseReadLock(SearchTable
, Count
);
378 /* We need the writer lock to expand/create the table */
379 AcquireWriteLock(SearchTable
);
381 /* Mark the table in use */
382 SearchTable
->Expanding
= TRUE
;
384 /* Wait for all the readers to finish */
385 TryWaitForReaders(SearchTable
);
390 /* Get the hash table again */
391 HashTable
= SearchTable
->HashTable
;
393 /* Check if exists now */
396 /* It does! Do what we wanted to do earlier. Get the hash... */
397 HashHandle
= &WSH_HASH_FROM_HANDLE(Handle
->Handle
, HashTable
);
399 /* Check if it doesn't exist */
402 /* Write it (no need for interlock, we have the RW lock) */
404 *HashHandle
= Handle
;
407 else if ((*HashHandle
)->Handle
== Handle
->Handle
)
409 /* Handle matches, write it (see comment above) */
410 OldHandle
= *HashHandle
;
411 *HashHandle
= Handle
;
415 /* No go, we need to expand the table. Remember the size now */
416 HandleCount
= HashTable
->Size
;
420 /* Table is empty, we have to create it */
425 /* Find a free prime */
426 for (i
= 0; HandleCount
>= SockPrimes
[i
]; i
++);
428 /* Check if we found one */
429 if (SockPrimes
[i
] != 0xFFFFFFFF)
432 HandleCount
= SockPrimes
[i
];
436 /* No primes left. Table is quite large, so simply double it */
440 /* Allocate the table */
441 NewHashTable
= HeapAlloc(GlobalHeap
,
443 FIELD_OFFSET(WSH_HASH_TABLE
,
444 Handles
[HandleCount
]));
446 /* Hopefully we have one now */
450 NewHashTable
->Size
= HandleCount
;
453 RtlZeroMemory(NewHashTable
->Handles
, HandleCount
* sizeof(PVOID
));
455 /* Insert us first */
456 WSH_HASH_FROM_HANDLE(Handle
->Handle
, NewHashTable
) = Handle
;
458 /* Now check if our old table had entries in it */
461 /* We need to move them */
462 for (i
= 0; i
< HashTable
->Size
; i
++)
464 /* Make sure the hash handle exists */
465 if (HashTable
->Handles
[i
])
468 HashHandle
= &WSH_HASH_FROM_HANDLE(HashTable
->
472 /* Check if it has a value */
475 /* It's empty, so just write the handle */
476 *HashHandle
= HashTable
->Handles
[i
];
480 /* Not empty :/... that implies a collision */
481 HeapFree(GlobalHeap
, 0, NewHashTable
);
487 /* Write the new hash table */
488 SearchTable
->HashTable
= NewHashTable
;
490 /* Wait for everyone to be done with it, then free it */
491 TryWaitForReaders(SearchTable
);
492 HeapFree(GlobalHeap
, 0, HashTable
);
496 /* It was empty, nothing to worry about */
497 SearchTable
->HashTable
= NewHashTable
;
500 /* Save the old handle */
505 /* There was no old handle */
510 /* Mark us as free, and release the write lock */
511 SearchTable
->Expanding
= FALSE
;
512 ReleaseWriteLock(SearchTable
);
516 /* Return the old handle */
522 WahReferenceContextByHandle(IN PWAH_HANDLE_TABLE Table
,
525 PWAH_HANDLE HashHandle
;
526 PWAH_SEARCH_TABLE SearchTable
;
527 PWAH_HASH_TABLE HashTable
;
530 /* Get the current Search Table */
531 SearchTable
= WSH_SEARCH_TABLE_FROM_HANDLE(Handle
, Table
);
534 AcquireReadLock(SearchTable
, &Count
);
536 /* Get the hash table and handle */
537 HashTable
= SearchTable
->HashTable
;
539 /* Check if it's valid, and if it's the one we want */
541 (HashHandle
= WSH_HASH_FROM_HANDLE(Handle
, HashTable
)) &&
542 (HashHandle
->Handle
== Handle
))
544 /* Reference the handle */
545 InterlockedIncrement(&HashHandle
->RefCount
);
553 /* Release the lock */
554 ReleaseReadLock(SearchTable
, Count
);
562 WahRemoveHandleContext(IN PWAH_HANDLE_TABLE Table
,
563 IN PWAH_HANDLE Handle
)
565 PWAH_HANDLE
*HashHandle
;
566 PWAH_SEARCH_TABLE SearchTable
;
567 PWAH_HASH_TABLE HashTable
;
568 DWORD ErrorCode
= ERROR_SUCCESS
;
570 /* Get the current Search Table */
571 SearchTable
= WSH_SEARCH_TABLE_FROM_HANDLE(Handle
->Handle
, Table
);
574 AcquireWriteLock(SearchTable
);
576 /* Get the hash table and handle */
577 HashTable
= SearchTable
->HashTable
;
578 HashHandle
= &WSH_HASH_FROM_HANDLE(Handle
->Handle
, HashTable
);
580 /* Make sure we have a handle, and write the new pointer */
581 if (HashHandle
&& (InterlockedCompareExchangePointer((PVOID
*)HashHandle
,
585 /* Wait for everyone to be done with it */
586 TryWaitForReaders(SearchTable
);
591 ErrorCode
= ERROR_INVALID_PARAMETER
;
594 /* Release the lock */
595 ReleaseWriteLock(SearchTable
);