ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

context.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.