Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencontext.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS WinSock 2 DLL 00004 * FILE: include/ws2_32.h 00005 * PURPOSE: WinSock 2 DLL header 00006 */ 00007 00008 /* INCLUDES ******************************************************************/ 00009 00010 #include "precomp.h" 00011 00012 /* DATA **********************************************************************/ 00013 00014 CRITICAL_SECTION WshHandleTableLock; 00015 HANDLE ghWriterEvent; 00016 DWORD gdwSpinCount = 0; 00017 DWORD gHandleToIndexMask; 00018 00019 CONST DWORD SockPrimes[] = 00020 { 00021 31, 61, 127, 257, 521, 1031, 2053, 00022 4099, 8191, 16381, 32749, 65537, 131071, 261983, 00023 -1 00024 }; 00025 00026 typedef volatile LONG VLONG; 00027 typedef VLONG *PVLONG; 00028 00029 /* DEFINES *******************************************************************/ 00030 00031 /* Yes, we "abuse" the lower bits */ 00032 #define WSH_SEARCH_TABLE_FROM_HANDLE(h, t) \ 00033 (&t->SearchTables[(((ULONG_PTR)h >> 2) & t->Mask)]) 00034 00035 #define WSH_HASH_FROM_HANDLE(h, hs) \ 00036 (hs->Handles[((ULONG_PTR)h % hs->Size)]) 00037 00038 #define AcquireWriteLock(t) \ 00039 EnterCriticalSection(&t->Lock); 00040 00041 #define ReleaseWriteLock(t) \ 00042 LeaveCriticalSection(&t->Lock); 00043 00044 /* FUNCTIONS *****************************************************************/ 00045 00046 VOID 00047 static __inline 00048 AcquireReadLock(IN PWAH_SEARCH_TABLE Table, 00049 IN PVLONG *Count) 00050 { 00051 LONG OldCount; 00052 00053 /* Start acquire loop */ 00054 do 00055 { 00056 /* Write and save count value */ 00057 *Count = Table->CurrentCount; 00058 OldCount = **Count; 00059 00060 /* Check if it's valid and try to increment it */ 00061 if ((OldCount > 0) && (InterlockedCompareExchange(*Count, 00062 OldCount + 1, 00063 OldCount) == OldCount)) 00064 { 00065 /* Everything went OK */ 00066 break; 00067 } 00068 } while (TRUE); 00069 } 00070 00071 VOID 00072 static __inline 00073 ReleaseReadLock(IN PWAH_SEARCH_TABLE Table, 00074 IN PVLONG Count) 00075 { 00076 /* Decrement the count. If we went below 0, someone is waiting... */ 00077 if (InterlockedDecrement(Count) < 0) 00078 { 00079 /* We use pulse since this is a shared event */ 00080 PulseEvent(ghWriterEvent); 00081 } 00082 } 00083 00084 VOID 00085 WINAPI 00086 DoWaitForReaders(IN PWAH_SEARCH_TABLE Table, 00087 IN PVLONG Counter) 00088 { 00089 HANDLE EventHandle; 00090 00091 /* Do a context switch */ 00092 SwitchToThread(); 00093 00094 /* Check if the counter is above one */ 00095 if (*Counter > 0) 00096 { 00097 /* 00098 * This shouldn't happen unless priorities are messed up. Do a wait so 00099 * that the threads with lower priority will get their chance now. 00100 */ 00101 if (!ghWriterEvent) 00102 { 00103 /* We don't even have an event! Allocate one manually... */ 00104 EventHandle = CreateEvent(NULL, TRUE, FALSE, NULL); 00105 if (EventHandle) 00106 { 00107 /* Save the event handle atomically */ 00108 if ((InterlockedCompareExchangePointer((PVOID*)&ghWriterEvent, 00109 EventHandle, 00110 NULL))) 00111 { 00112 /* Someone beat us to it, close ours */ 00113 CloseHandle(EventHandle); 00114 } 00115 } 00116 else 00117 { 00118 /* Things couldn't get worse for us. Do a last-resort hack */ 00119 while (*Counter > 0) Sleep(10); 00120 } 00121 } 00122 00123 /* 00124 * Our event is ready. Tell the others to signal us by making sure 00125 * that the last counter will be -1, notifying the last thread of our 00126 * request. 00127 */ 00128 if (InterlockedDecrement(Counter) >= 0) 00129 { 00130 /* Keep looping */ 00131 do 00132 { 00133 /* Wait in tiny bursts, so we can catch the PulseEvent */ 00134 WaitForSingleObject(ghWriterEvent, 10); 00135 } while (*Counter >= 0); 00136 } 00137 } 00138 } 00139 00140 VOID 00141 static __inline 00142 TryWaitForReaders(IN PWAH_SEARCH_TABLE Table) 00143 { 00144 PVLONG OldCount = Table->CurrentCount; 00145 LONG SpinCount; 00146 00147 /* See which counter is being used */ 00148 if (OldCount == &Table->Count1) 00149 { 00150 /* Use counter 2 now */ 00151 Table->Count2 = 1; 00152 Table->CurrentCount = &Table->Count2; 00153 } 00154 else 00155 { 00156 /* Use counter 1 now */ 00157 Table->Count1 = 1; 00158 Table->CurrentCount = &Table->Count1; 00159 } 00160 00161 /* Decrease the old count to block new readers */ 00162 if (InterlockedDecrement(OldCount) > 0) 00163 { 00164 /* On an MP machine, spin a bit first */ 00165 if (Table->SpinCount) 00166 { 00167 /* Get the spincount and loop it */ 00168 SpinCount = Table->SpinCount; 00169 while (*OldCount > 0) 00170 { 00171 /* Check if the spin failed */ 00172 if (--SpinCount <= 0) break; 00173 } 00174 } 00175 00176 /* Check one last time if someone is still active */ 00177 if (*OldCount > 0) 00178 { 00179 /* Yep, we'll have to do a blocking (slow) wait */ 00180 DoWaitForReaders(Table, OldCount); 00181 } 00182 } 00183 } 00184 00185 DWORD 00186 WINAPI 00187 WahCreateHandleContextTable(OUT PWAH_HANDLE_TABLE *Table) 00188 { 00189 DWORD ErrorCode; 00190 PWAH_HANDLE_TABLE LocalTable; 00191 DWORD i; 00192 00193 /* Enter the prolog, make sure we're initialized */ 00194 ErrorCode = WS2HELP_PROLOG(); 00195 if (ErrorCode != ERROR_SUCCESS) return ErrorCode; 00196 00197 /* Assume NULL */ 00198 *Table = NULL; 00199 00200 /* Allocate enough tables */ 00201 LocalTable = HeapAlloc(GlobalHeap, 00202 0, 00203 FIELD_OFFSET(WSH_HANDLE_TABLE, 00204 SearchTables[gHandleToIndexMask + 1])); 00205 00206 /* Make sure it was allocated */ 00207 if (!LocalTable) return WSA_NOT_ENOUGH_MEMORY; 00208 00209 /* Set the mask for the table */ 00210 LocalTable->Mask = gHandleToIndexMask; 00211 00212 /* Now initialize every table */ 00213 for (i = 0; i <= gHandleToIndexMask; i++) 00214 { 00215 /* No hash table yet */ 00216 LocalTable->SearchTables[i].HashTable = NULL; 00217 00218 /* Set the current count */ 00219 LocalTable->SearchTables[i].CurrentCount = &LocalTable->SearchTables[i].Count1; 00220 00221 /* Initialize the counts */ 00222 LocalTable->SearchTables[i].Count1 = 1; 00223 LocalTable->SearchTables[i].Count2 = 0; 00224 00225 /* Set expanding state and spin count */ 00226 LocalTable->SearchTables[i].Expanding = FALSE; 00227 LocalTable->SearchTables[i].SpinCount = gdwSpinCount; 00228 00229 /* Initialize the lock */ 00230 (VOID)InitializeCriticalSectionAndSpinCount(&LocalTable-> 00231 SearchTables[i].Lock, 00232 gdwSpinCount); 00233 } 00234 00235 /* Return pointer */ 00236 *Table = LocalTable; 00237 00238 /* Return success */ 00239 return ERROR_SUCCESS; 00240 } 00241 00242 DWORD 00243 WINAPI 00244 WahDestroyHandleContextTable(IN PWAH_HANDLE_TABLE Table) 00245 { 00246 DWORD i; 00247 00248 /* Make sure the table is valid */ 00249 if (!Table) 00250 { 00251 /* No valid table */ 00252 return ERROR_INVALID_PARAMETER; 00253 } 00254 00255 /* Loop each search table */ 00256 for (i = 0; i <= Table->Mask; i++) 00257 { 00258 /* Check if there's a table here */ 00259 if (Table->SearchTables[i].HashTable) 00260 { 00261 /* Free it */ 00262 HeapFree(GlobalHeap, 0, Table->SearchTables[i].HashTable); 00263 } 00264 00265 /* Delete the lock */ 00266 DeleteCriticalSection(&Table->SearchTables[i].Lock); 00267 } 00268 00269 /* Delete the table */ 00270 HeapFree(GlobalHeap, 0, Table); 00271 00272 /* Return success */ 00273 return ERROR_SUCCESS; 00274 } 00275 00276 BOOL 00277 WINAPI 00278 WahEnumerateHandleContexts(IN PWAH_HANDLE_TABLE Table, 00279 IN PWAH_HANDLE_ENUMERATE_PROC Callback, 00280 IN PVOID Context) 00281 { 00282 DWORD i, j; 00283 PWAH_SEARCH_TABLE SearchTable; 00284 PWAH_HASH_TABLE HashTable; 00285 PWAH_HANDLE Handle; 00286 BOOL GoOn = TRUE; 00287 00288 /* Loop the table */ 00289 for (i = 0; i <= Table->Mask; i++) 00290 { 00291 /* Get the Search table */ 00292 SearchTable = &Table->SearchTables[i]; 00293 00294 /* Lock it */ 00295 AcquireWriteLock(SearchTable); 00296 00297 /* Mark us as expanding and wait for everyone */ 00298 SearchTable->Expanding = TRUE; 00299 TryWaitForReaders(SearchTable); 00300 00301 /* Get the hash table */ 00302 HashTable = SearchTable->HashTable; 00303 00304 /* Make sure it exists */ 00305 if (HashTable) 00306 { 00307 /* Loop every handle in it */ 00308 for (j = 0; j < HashTable->Size; j++) 00309 { 00310 /* Get this handle */ 00311 Handle = HashTable->Handles[j]; 00312 if (!Handle) continue; 00313 00314 /* Call the callback proc */ 00315 GoOn = Callback(Context, Handle); 00316 if (!GoOn) break; 00317 } 00318 } 00319 00320 /* Disable the expansion bit and release the lock */ 00321 SearchTable->Expanding = FALSE; 00322 ReleaseWriteLock(SearchTable); 00323 00324 /* Check again if we should leave */ 00325 if (!GoOn) break; 00326 } 00327 00328 /* return */ 00329 return GoOn; 00330 } 00331 00332 PWAH_HANDLE 00333 WINAPI 00334 WahInsertHandleContext(IN PWAH_HANDLE_TABLE Table, 00335 IN PWAH_HANDLE Handle) 00336 { 00337 PWAH_HANDLE *HashHandle, OldHandle; 00338 PVLONG Count; 00339 PWAH_HASH_TABLE HashTable, NewHashTable; 00340 DWORD HandleCount, i; 00341 PWAH_SEARCH_TABLE SearchTable; 00342 00343 /* Get the current Search Table */ 00344 SearchTable = WSH_SEARCH_TABLE_FROM_HANDLE(Handle->Handle, Table); 00345 00346 /* Start loop */ 00347 do 00348 { 00349 /* Get reader lock */ 00350 AcquireReadLock(SearchTable, &Count); 00351 00352 /* Get the hash table */ 00353 HashTable = SearchTable->HashTable; 00354 00355 /* Make sure we are not expanding, and that the table is there */ 00356 if (!(SearchTable->Expanding) && (HashTable)) 00357 { 00358 /* Get the hash handle */ 00359 HashHandle = &WSH_HASH_FROM_HANDLE(Handle->Handle, HashTable); 00360 00361 /* Do the insert */ 00362 if (InterlockedCompareExchangePointer((PVOID*)HashHandle, 00363 Handle, 00364 NULL) == NULL) 00365 { 00366 /* Success, release the reader lock */ 00367 ReleaseReadLock(SearchTable, Count); 00368 00369 /* Save old handle */ 00370 OldHandle = Handle; 00371 break; 00372 } 00373 } 00374 00375 /* Release the read lock since we're done with it now */ 00376 ReleaseReadLock(SearchTable, Count); 00377 00378 /* We need the writer lock to expand/create the table */ 00379 AcquireWriteLock(SearchTable); 00380 00381 /* Mark the table in use */ 00382 SearchTable->Expanding = TRUE; 00383 00384 /* Wait for all the readers to finish */ 00385 TryWaitForReaders(SearchTable); 00386 00387 /* Start loop */ 00388 do 00389 { 00390 /* Get the hash table again */ 00391 HashTable = SearchTable->HashTable; 00392 00393 /* Check if exists now */ 00394 if (HashTable) 00395 { 00396 /* It does! Do what we wanted to do earlier. Get the hash... */ 00397 HashHandle = &WSH_HASH_FROM_HANDLE(Handle->Handle, HashTable); 00398 00399 /* Check if it doesn't exist */ 00400 if (!(*HashHandle)) 00401 { 00402 /* Write it (no need for interlock, we have the RW lock) */ 00403 OldHandle = Handle; 00404 *HashHandle = Handle; 00405 break; 00406 } 00407 else if ((*HashHandle)->Handle == Handle->Handle) 00408 { 00409 /* Handle matches, write it (see comment above) */ 00410 OldHandle = *HashHandle; 00411 *HashHandle = Handle; 00412 break; 00413 } 00414 00415 /* No go, we need to expand the table. Remember the size now */ 00416 HandleCount = HashTable->Size; 00417 } 00418 else 00419 { 00420 /* Table is empty, we have to create it */ 00421 HandleCount = 0; 00422 } 00423 00424 ExpandTable: 00425 /* Find a free prime */ 00426 for (i = 0; HandleCount >= SockPrimes[i]; i++); 00427 00428 /* Check if we found one */ 00429 if (SockPrimes[i] != 0xFFFFFFFF) 00430 { 00431 /* Use the prime */ 00432 HandleCount = SockPrimes[i]; 00433 } 00434 else 00435 { 00436 /* No primes left. Table is quite large, so simply double it */ 00437 HandleCount *= 2; 00438 } 00439 00440 /* Allocate the table */ 00441 NewHashTable = HeapAlloc(GlobalHeap, 00442 0, 00443 FIELD_OFFSET(WSH_HASH_TABLE, 00444 Handles[HandleCount])); 00445 00446 /* Hopefully we have one now */ 00447 if (NewHashTable) 00448 { 00449 /* Set its size */ 00450 NewHashTable->Size = HandleCount; 00451 00452 /* Initialize it */ 00453 RtlZeroMemory(NewHashTable->Handles, HandleCount * sizeof(PVOID)); 00454 00455 /* Insert us first */ 00456 WSH_HASH_FROM_HANDLE(Handle->Handle, NewHashTable) = Handle; 00457 00458 /* Now check if our old table had entries in it */ 00459 if (HashTable) 00460 { 00461 /* We need to move them */ 00462 for (i = 0; i < HashTable->Size; i++) 00463 { 00464 /* Make sure the hash handle exists */ 00465 if (HashTable->Handles[i]) 00466 { 00467 /* Get it */ 00468 HashHandle = &WSH_HASH_FROM_HANDLE(HashTable-> 00469 Handles[i]->Handle, 00470 NewHashTable); 00471 00472 /* Check if it has a value */ 00473 if (!(*HashHandle)) 00474 { 00475 /* It's empty, so just write the handle */ 00476 *HashHandle = HashTable->Handles[i]; 00477 } 00478 else 00479 { 00480 /* Not empty :/... that implies a collision */ 00481 HeapFree(GlobalHeap, 0, NewHashTable); 00482 goto ExpandTable; 00483 } 00484 } 00485 } 00486 00487 /* Write the new hash table */ 00488 SearchTable->HashTable = NewHashTable; 00489 00490 /* Wait for everyone to be done with it, then free it */ 00491 TryWaitForReaders(SearchTable); 00492 HeapFree(GlobalHeap, 0, HashTable); 00493 } 00494 else 00495 { 00496 /* It was empty, nothing to worry about */ 00497 SearchTable->HashTable = NewHashTable; 00498 } 00499 00500 /* Save the old handle */ 00501 OldHandle = Handle; 00502 } 00503 else 00504 { 00505 /* There was no old handle */ 00506 OldHandle = Handle; 00507 } 00508 } while (0); 00509 00510 /* Mark us as free, and release the write lock */ 00511 SearchTable->Expanding = FALSE; 00512 ReleaseWriteLock(SearchTable); 00513 break; 00514 } while (1); 00515 00516 /* Return the old handle */ 00517 return OldHandle; 00518 } 00519 00520 PWAH_HANDLE 00521 WINAPI 00522 WahReferenceContextByHandle(IN PWAH_HANDLE_TABLE Table, 00523 IN HANDLE Handle) 00524 { 00525 PWAH_HANDLE HashHandle; 00526 PWAH_SEARCH_TABLE SearchTable; 00527 PWAH_HASH_TABLE HashTable; 00528 PVLONG Count; 00529 00530 /* Get the current Search Table */ 00531 SearchTable = WSH_SEARCH_TABLE_FROM_HANDLE(Handle, Table); 00532 00533 /* Lock it */ 00534 AcquireReadLock(SearchTable, &Count); 00535 00536 /* Get the hash table and handle */ 00537 HashTable = SearchTable->HashTable; 00538 00539 /* Check if it's valid, and if it's the one we want */ 00540 if ((HashTable) && 00541 (HashHandle = WSH_HASH_FROM_HANDLE(Handle, HashTable)) && 00542 (HashHandle->Handle == Handle)) 00543 { 00544 /* Reference the handle */ 00545 InterlockedIncrement(&HashHandle->RefCount); 00546 } 00547 else 00548 { 00549 /* Invalid handle */ 00550 HashHandle = NULL; 00551 } 00552 00553 /* Release the lock */ 00554 ReleaseReadLock(SearchTable, Count); 00555 00556 /* Return */ 00557 return HashHandle; 00558 } 00559 00560 DWORD 00561 WINAPI 00562 WahRemoveHandleContext(IN PWAH_HANDLE_TABLE Table, 00563 IN PWAH_HANDLE Handle) 00564 { 00565 PWAH_HANDLE *HashHandle; 00566 PWAH_SEARCH_TABLE SearchTable; 00567 PWAH_HASH_TABLE HashTable; 00568 DWORD ErrorCode = ERROR_SUCCESS; 00569 00570 /* Get the current Search Table */ 00571 SearchTable = WSH_SEARCH_TABLE_FROM_HANDLE(Handle->Handle, Table); 00572 00573 /* Lock it */ 00574 AcquireWriteLock(SearchTable); 00575 00576 /* Get the hash table and handle */ 00577 HashTable = SearchTable->HashTable; 00578 HashHandle = &WSH_HASH_FROM_HANDLE(Handle->Handle, HashTable); 00579 00580 /* Make sure we have a handle, and write the new pointer */ 00581 if (HashHandle && (InterlockedCompareExchangePointer((PVOID*)HashHandle, 00582 NULL, 00583 Handle) == Handle)) 00584 { 00585 /* Wait for everyone to be done with it */ 00586 TryWaitForReaders(SearchTable); 00587 } 00588 else 00589 { 00590 /* Invalid handle */ 00591 ErrorCode = ERROR_INVALID_PARAMETER; 00592 } 00593 00594 /* Release the lock */ 00595 ReleaseWriteLock(SearchTable); 00596 00597 /* Return */ 00598 return ErrorCode; 00599 } 00600 00601 /* EOF */ Generated on Fri May 25 2012 04:18:17 for ReactOS by
1.7.6.1
|