|
|
1.1.1.2 ! root 1: /****************************************************************************\ ! 2: ** ** ! 3: ** Microsoft Developer Support ** ! 4: ** Copyright (c) 1992 Microsoft Corporation ** ! 5: ** ** ! 6: ** MODULE: DataBase ** ! 7: ** ** ! 8: ** ** ! 9: ** PURPOSE: Demonstrates the basic concepts of one of the classical ** ! 10: ** synchronous problems. A derivative of the Reader/Writer ** ! 11: ** problem. In which one must allow access to each without ** ! 12: ** jeopardizing the Database. ** ! 13: ** ** ! 14: ** INTERNAL FUNCTIONS: ** ! 15: ** ** ! 16: ** InitializeDataBase ** ! 17: ** CloseDataBase ** ! 18: ** InitializeSubsystem ** ! 19: ** InitApp ** ! 20: ** CleanupSubsystem ** ! 21: ** CleanupApp ** ! 22: ** TestInitExitPoint ** ! 23: ** ErrorMsg ** ! 24: ** DebugMsg ** ! 25: ** ** ! 26: ** ** ! 27: ** EXPORTED FUNCTIONS ** ! 28: ** ** ! 29: ** ReadDataBase ** ! 30: ** WriteDataBase ** ! 31: ** ** ! 32: ** ** ! 33: ** COMMENTS: ** ! 34: ** ** ! 35: ** This also demonstrates how to have both global shared data ** ! 36: ** instance data. What I've done is named the shared section ** ! 37: ** with the #pragma data_seg( SEGNAME, "" ) statement and ** ! 38: ** referenced this in the DEF file as READ/WRITE/SHARED. ** ! 39: ** ** ! 40: \***************************************************************************/ ! 41: ! 42: ! 43: ! 44: 1.1 root 45: #define STRICT 46: #define NOMINMAX 47: #include <windows.h> 48: #include <stdio.h> 49: #include <string.h> 50: #include <stdlib.h> 51: 52: 53: typedef HANDLE HMUTEX ; 54: typedef HANDLE HSEM ; 55: typedef HANDLE HEVENT ; 56: 57: /* Names for synchronization objects */ 58: #define SEM1 "semph1" 59: #define MUTX1 "mutx1" 60: #define EVENT1 "event1" 61: #define EVENT2 "event2" 62: #define EVENT3 "evnet3" 63: #define EVENT4 "event4" 64: 65: #define MAX 10 66: 67: #define SIGNALED 0 68: #define WAIT_ERROR 0xFFFFFFFF 69: 70: 71: /*global Variables */ 1.1.1.2 ! root 72: ! 73: ! 74: /* Put gUserCount in a GLOBAL section. This is because first time ! 75: * initialization is handled differently than others ! 76: */ ! 77: ! 78: #pragma data_seg("MYSEG", "") ! 79: 1.1 root 80: int gUserCount = 0 ; 1.1.1.2 ! root 81: ! 82: #pragma data_seg(".data", "") ! 83: ! 84: ! 85: ! 86: 1.1 root 87: HMUTEX ghMutex ; 88: HSEM ghSemaphore ; 89: HEVENT ghReadEvent1, ghReadEvent2, ghWriteEvent1, ghWriteEvent2 ; 90: UINT cReadQueue, cWriteQueue, cReadQueueEx ; 91: UINT cRead, cWrite ; 92: BOOL InWrite ; 93: 94: /* 95: * This is the data type which this 96: * 97: */ 98: 99: char *DataBase[MAX] ; 100: 101: 102: 103: /***** Private functions *****/ 104: 105: BOOL InitializeSubsystem ( VOID ) ; 106: BOOL InitApp ( VOID ) ; 107: BOOL CleanupSubsystem ( VOID ) ; 108: BOOL CleanupApp ( VOID ) ; 109: BOOL InitializeDataBase ( VOID ) ; 110: BOOL CloseDataBase ( VOID ) ; 111: BOOL GetData ( PSZ psz ) ; 112: BOOL PutData ( PSZ psz ) ; 113: 114: 115: /***** DLL Entry/Exit point *****/ 116: 117: BOOL APIENTRY DLLInitExitPoint ( HANDLE hModule, DWORD dwReason, LPVOID lpReserved ) ; 118: 119: 120: /***** Debuging functions *****/ 121: 122: VOID ErrorMsg ( PSZ psz ) ; 123: VOID DebugMsg ( PSZ psz ) ; 124: 125: 126: 127: 128: 129: /***************************************************************************\ 130: ** ** 131: ** FUNCTION: ErrorMsg(LPTSTR) ** 132: ** ** 133: ** PURPOSE: Prints out an error message the return code of the last API ** 134: ** to fail. ** 135: ** ** 136: ** INPUT: psz: This string is a description of where the code failed in ** 137: ** the module ** 138: ** ** 139: ** OUTPUT: None ** 140: ** ** 141: \****************************************************************************/ 142: 143: VOID ErrorMsg ( PSZ psz ) 144: { 145: printf ("\n%s: return code = %d\n", psz, GetLastError()) ; 146: } 147: 148: 149: /***************************************************************************\ 150: ** ** 151: ** FUNCTION: DebugMsg(LPTSTR) ** 152: ** ** 153: ** PURPOSE: Prints out an debug message ** 154: ** ** 155: ** INPUT: psz: This string is used for informational purposes only ** 156: ** ** 157: ** OUTPUT: None ** 158: ** ** 159: \****************************************************************************/ 160: 161: 1.1.1.2 ! root 162: VOID DebugMsg ( PSZ psz ) 1.1 root 163: { 164: printf ( psz ) ; 165: } 166: 167: 168: /***************************************************************************\ 169: ** ** 170: ** FUNCTION: DLLInitExitPoint ** 171: ** ** 172: ** PURPOSE: Handles both initialization and cleanup of DLL ** 173: ** ** 174: ** INPUT: Handle to module calling this DLL. Flag which indicates ** 175: ** why the DLL entry routine is being called. ** 176: ** ** 177: ** OUTPUT: None ** 178: ** ** 179: ** ERRORS: Returns FALSE if an error occured while the process was being ** 180: ** attached. Any other time the return value is ignored. ** 181: ** ** 182: ** COMMENTS: This function takes place of the LIBMAIN/LIBENTRY and WEP ** 183: ** ** 184: ** Even if no initialization is need this function must return ** 185: ** ** 186: ** ** 187: \****************************************************************************/ 188: 189: 190: 191: BOOL APIENTRY DLLInitExitPoint ( HANDLE hModule, DWORD dwReason, LPVOID lpReserved ) 192: { 193: 194: BOOL bSuccess ; 195: UNREFERENCED_PARAMETER ( hModule ) ; 196: UNREFERENCED_PARAMETER ( lpReserved ) ; 197: 198: 199: if ( dwReason == DLL_PROCESS_ATTACH ) { 200: 201: gUserCount++ ; 202: 203: printf ( "\nNumber of clients currently using this are %d\n", gUserCount ) ; 204: 205: if ( gUserCount == 1 ) 206: bSuccess = InitializeSubsystem ( ) ; 207: else 208: bSuccess = InitApp ( ) ; 209: } 210: 211: else if ( dwReason == DLL_PROCESS_DETACH ) { 212: 213: printf ( "\nCleaning up subsystem ...\n" ) ; 214: printf ( "Number of clients currently using this are %d\n", gUserCount ) ; 215: 216: if ( gUserCount == 1 ) 217: bSuccess = CleanupSubsystem ( ) ; 218: else 219: bSuccess = CleanupApp ( ) ; 220: 221: gUserCount-- ; 222: 223: } 224: 225: 226: return ( bSuccess ) ; 227: } 228: 229: 230: /***************************************************************************\ 231: ** ** 232: ** FUNCTION: InitializeSubsystem ** 233: ** ** 234: ** PURPOSE: Sets up the required synchronization objects to insure both ** 235: ** system performance and data integrity. This is only done ** 236: ** once; by the first process that attaches itself to the DLL ** 237: ** ** 238: ** INPUT: None ** 239: ** ** 240: ** OUTPUT: Returns TRUE if successfull otherwise FALSE ** 241: ** ** 242: \****************************************************************************/ 243: 244: BOOL InitializeSubsystem ( VOID ) 245: { 246: LONG cSemMax = 5; 247: BOOL bSuccess ; 248: 249: DebugMsg ( "InitializeSubsystem\n" ) ; 250: 251: ghSemaphore = CreateSemaphore ( NULL, // No security descriptor 252: 253: 0, // Initial count of zero so 254: // access to database is blocked 255: // till initialization completed 256: cSemMax, 257: // Maximun threads allowed to 258: // access the database at one time 259: SEM1) ; // No name 260: 261: if ( !ghSemaphore ) 262: { 263: ErrorMsg ( "Error Creating semaphore" ) ; 264: return ( FALSE ) ; 265: } 266: 267: 268: ghMutex = CreateMutex ( NULL, // No security descriptor 269: TRUE, // Block access till database 270: // is setup 271: MUTX1 ) ; // No name 272: if ( !ghMutex ) 273: { 274: ErrorMsg ( "Error Creating Mutex" ) ; 275: return ( FALSE ) ; 276: } 277: 278: ghReadEvent1 = CreateEvent ( NULL, // No security descriptor 279: FALSE, // Use manual reset so all 280: // waiting threads get signaled 281: FALSE, // Set to non-signaled state 282: EVENT1 ) ; 283: 284: 285: if ( !ghReadEvent1 ) 286: { 287: ErrorMsg ( "Error Creating ghReadEvent1" ) ; 288: return ( FALSE ) ; 289: } 290: 291: ghWriteEvent1 = CreateEvent ( NULL, // No security descriptor 292: FALSE, // Use manual reset so all 293: // waiting threads get signaled 294: FALSE, // Set to non-signaled state 295: EVENT2 ) ; 296: 297: 298: if ( !ghWriteEvent1 ) 299: { 300: ErrorMsg ( "Error Creating ghWriteEvent1" ) ; 301: return ( FALSE ) ; 302: } 303: 304: ghReadEvent2 = CreateEvent ( NULL, // No security descriptor 305: FALSE, // Use manual reset so all 306: // waiting threads get signaled 307: FALSE, // Set to non-signaled state 308: EVENT3 ) ; 309: 310: 311: if ( !ghReadEvent2 ) 312: { 313: ErrorMsg ( "Error Creating ghReadEvent2" ) ; 314: return ( FALSE ) ; 315: } 316: 317: ghWriteEvent2 = CreateEvent ( NULL, // No security descriptor 318: FALSE, // Use manual reset so all 319: // waiting threads get signaled 320: FALSE, // Set to non-signaled state 321: EVENT4 ) ; 322: 323: if ( !ghWriteEvent2 ) 324: { 325: ErrorMsg ( "Error Creating ghWriteEvent2" ) ; 326: return ( FALSE ) ; 327: } 328: 329: bSuccess = InitializeDataBase () ; 330: 331: 332: /* 333: * Now that all the initialization is done it's save to 334: * release the semaphore and mutex. 335: * 336: */ 337: 338: if ( !ReleaseSemaphore ( ghSemaphore, // Handle to semaphore 339: cSemMax, // Size to increment 340: NULL ) ) // Don't care about previous value 341: { 342: ErrorMsg ( "Error releasing semaphore" ) ; 343: return ( FALSE ) ; 344: } 345: 346: 347: if ( !ReleaseMutex ( ghMutex ) ) // Handle to semaphore 348: { 349: ErrorMsg ( "Error releasing mutex" ) ; 350: return ( FALSE ) ; 351: } 352: 353: return ( bSuccess ) ; 354: } 355: 356: /***************************************************************************\ 357: ** ** 358: ** FUNCTION: InitApp ** 359: ** ** 360: ** PURPOSE: Sets up the required synchronization objects to insure both ** 361: ** system performance and data integrity. This is done each ** 362: ** a process attaches itself to this DLL ** 363: ** ** 364: ** INPUT: None ** 365: ** ** 366: ** OUTPUT: Returns TRUE if successfull otherwise FALSE ** 367: ** ** 368: \****************************************************************************/ 369: 370: BOOL InitApp ( VOID ) 371: { 372: 373: DebugMsg ( "InitApp\n" ) ; 374: 375: ghSemaphore = OpenSemaphore ( SEMAPHORE_ALL_ACCESS, // 376: FALSE, // No inheritance 377: SEM1 ) ; // No name 378: 379: if ( !ghSemaphore ) 380: { 381: ErrorMsg ( "Error Opening semaphore" ) ; 382: return ( FALSE ) ; 383: } 384: 385: 386: ghMutex = OpenMutex ( MUTEX_ALL_ACCESS, // 387: FALSE, // No inheritance 388: MUTX1 ) ; // No name 389: if ( !ghMutex ) 390: { 391: ErrorMsg ( "Error Opening Mutex" ) ; 392: return ( FALSE ) ; 393: } 394: 395: ghReadEvent1 = OpenEvent ( EVENT_ALL_ACCESS, // 396: FALSE, // No inheritance 397: EVENT1 ) ; // 398: 399: if ( !ghReadEvent1 ) 400: { 401: ErrorMsg ( "Error Opening ghReadEvent1" ) ; 402: return ( FALSE ) ; 403: } 404: 405: 406: ghWriteEvent1 = OpenEvent ( EVENT_ALL_ACCESS, // 407: FALSE, // No inheritance 408: EVENT2 ) ; // 409: 410: 411: if ( !ghWriteEvent1 ) 412: { 413: ErrorMsg ( "Error Opening ghWriteEvent1" ) ; 414: return ( FALSE ) ; 415: } 416: 417: ghReadEvent2 = OpenEvent ( EVENT_ALL_ACCESS, // 418: FALSE, // No inheritance 419: EVENT3 ) ; // 420: 421: if ( !ghReadEvent2 ) 422: { 423: ErrorMsg ( "Error Opening ghReadEvent2" ) ; 424: return ( FALSE ) ; 425: } 426: 427: 428: ghWriteEvent2 = OpenEvent ( EVENT_ALL_ACCESS, // 429: FALSE, // No inheritance 430: EVENT4 ) ; // 431: 432: 433: if ( !ghWriteEvent2 ) 434: { 435: ErrorMsg ( "Error Opening ghWriteEvent2" ) ; 436: return ( FALSE ) ; 437: } 438: 439: return ( TRUE ) ; 440: } 441: 442: 443: 444: BOOL CleanupSubsystem ( VOID ) 445: { 446: DebugMsg ( "CleanupSubsystem\n" ) ; 447: 448: if ( !CloseHandle ( ghSemaphore ) ) 449: ErrorMsg ( "Error Closing Semaphore" ) ; 450: 451: if ( !CloseHandle ( ghMutex ) ) 452: ErrorMsg ( "Error Closing Mutex" ) ; 453: 454: if ( !CloseHandle ( ghReadEvent1 ) ) 455: ErrorMsg ( "Error Closing Event" ) ; 456: 457: if ( !CloseHandle ( ghWriteEvent1 ) ) 458: ErrorMsg ( "Error Closing Event" ) ; 459: 460: CloseDataBase ( ) ; 461: 462: return ( TRUE ) ; 463: } 464: 465: 466: /***************************************************************************\ 467: ** ** 468: ** FUNCTION: CleanupApp ** 469: ** ** 470: ** PURPOSE: Cleans up (closes) the synchronization objects. ** 471: ** This is done each a process attaches itself to this DLL ** 472: ** ** 473: ** INPUT: None ** 474: ** ** 475: ** OUTPUT: Returns TRUE if successfull otherwise FALSE ** 476: ** ** 477: \****************************************************************************/ 478: 479: BOOL CleanupApp ( VOID ) 480: { 481: DebugMsg ( "CleanupApp\n" ) ; 482: 483: if ( !CloseHandle ( ghSemaphore ) ) 484: ErrorMsg ( "Error Closing Semaphore" ) ; 485: 486: if ( !CloseHandle ( ghMutex ) ) 487: ErrorMsg ( "Error Closing Mutex" ) ; 488: 489: if ( !CloseHandle ( ghReadEvent1 ) ) 490: ErrorMsg ( "Error Closing Event" ) ; 491: 492: if ( !CloseHandle ( ghWriteEvent1 ) ) 493: ErrorMsg ( "Error Closing Event" ) ; 494: 495: return ( TRUE ) ; 496: } 497: 498: 499: /***************************************************************************\ 500: ** ** 501: ** FUNCTION: InitializeDataBase ** 502: ** ** 503: ** PURPOSE: 504: ** 505: ** ** 506: ** INPUT: None ** 507: ** ** 508: ** OUTPUT: Returns TRUE if successfull otherwise FALSE ** 509: ** ** 510: \****************************************************************************/ 511: 512: BOOL InitializeDataBase ( VOID ) 513: { 514: UINT i ; 515: 516: DebugMsg ( "Initializing database\n" ) ; 517: 518: for ( i=0; i< MAX; i++ ) 519: PutData ( "Unintialized" ) ; 520: 521: return ( TRUE ) ; 522: } 523: 524: 525: /***************************************************************************\ 526: ** ** 527: ** FUNCTION: CloseDataBase ** 528: ** ** 529: ** PURPOSE: 530: ** 531: ** ** 532: ** INPUT: None ** 533: ** ** 534: ** OUTPUT: Returns TRUE if successfull otherwise FALSE ** 535: ** ** 536: \****************************************************************************/ 537: 538: BOOL CloseDataBase ( VOID ) 539: { 540: DebugMsg ( "Closing database\n" ) ; 541: return ( TRUE ) ; 542: } 543: 544: 545: /***************************************************************************\ 546: ** ** 547: ** FUNCTION: ReadDataBase ( PSZ ** 548: ** ** 549: ** PURPOSE: Fetches data out of the database ** 550: ** ** 551: ** INPUT: None ** 552: ** ** 553: ** OUTPUT: Pointer to data ** 554: ** ** 555: ** ERROR: Returns False if it can not complete the request ** 556: ** ** 557: ** COMMENTS: A reader can not enter the database if ** 558: ** ** 559: ** 1) A writer already is in the database ** 560: ** 2) The maximum number of readers are in the database ** 561: ** ** 562: ** A new reader can not enter the databse if ** 563: ** ** 564: ** 1) A writer is waiting ** 565: ** ** 566: \****************************************************************************/ 567: 568: 569: BOOL APIENTRY ReadDataBase ( PSZ psz1, PSZ psz2 ) 570: { 571: BOOL bSuccess ; 572: DWORD dwSuccess ; 573: UNREFERENCED_PARAMETER ( psz2 ) ; 574: 575: // DebugMsg ("In ReadDataBase\n" ) ; 576: 577: cReadQueueEx++ ; 578: dwSuccess = SIGNALED ; 579: 580: if ( cWriteQueue ) // Block if Writer waiting 581: dwSuccess = WaitForSingleObject ( ghReadEvent1, 0xFFFFFFFF ) ; 582: // dwSuccess = WaitForSingleObject ( ghReadEvent1, 5000 ) ; 583: 584: cReadQueue++ ; // Reader entering queue 585: cReadQueueEx-- ; 586: 587: if ( dwSuccess != SIGNALED ) 588: { 589: ErrorMsg ( "ReadDatabase: Error Waiting for ghReadEvent1" ) ; 590: bSuccess = FALSE ; 591: } 592: else 593: { 594: /* 595: * Only let N readers in the queue at one time 596: */ 597: switch ( WaitForSingleObject ( ghSemaphore, 0xFFFFFFFF ) ) 598: // switch ( WaitForSingleObject ( ghSemaphore, 3000 ) ) 599: { 600: case SIGNALED: 601: try { 602: if ( InWrite ) // Block if Writer in database 603: dwSuccess = WaitForSingleObject ( ghReadEvent2, 0xFFFFFFFF ) ; 604: // dwSuccess = WaitForSingleObject ( ghReadEvent2, 1500 ) ; 605: 606: cRead++ ; // Number readers in database 607: cReadQueue-- ; // Reader leaving queue 608: 609: /* 610: * Signal Writer if no Reader waiting 611: * 612: */ 613: if ( !cReadQueue ) 614: bSuccess = SetEvent ( ghWriteEvent1 ) ; 615: 616: if ( dwSuccess == SIGNALED ) 617: { 618: bSuccess = GetData ( psz1 ) ; // Read data 619: cRead-- ; 620: /* 621: * Signal Writer if no Reader in database 622: * 623: */ 624: 625: if ( !cRead ) 626: bSuccess = SetEvent ( ghWriteEvent2 ) ; 627: 628: ReleaseSemaphore ( ghSemaphore, // Let next waiting 629: 1, // reader in the queue 630: NULL ) ; 631: } 632: else 633: { 634: cRead-- ; 635: /* 636: * Signal Writer if no Reader in database 637: * 638: */ 639: 640: if ( !cRead ) 641: bSuccess = SetEvent ( ghWriteEvent2 ) ; 642: 643: bSuccess = FALSE ; 644: DebugMsg ( "ReadDataBase: Error Waiting for ghReadEvent2\n" ) ; 645: } 646: } 647: finally { 648: // what if these is already decremented above???? 649: cRead-- ; 650: /* 651: * Signal Writer if no Reader in database 652: * 653: */ 654: 655: if ( !cRead ) 656: bSuccess = SetEvent ( ghWriteEvent2 ) ; 657: 658: /* 659: * Signal Writer if no Reader in queue 660: * 661: */ 662: if ( !cReadQueue ) 663: bSuccess = SetEvent ( ghWriteEvent1 ) ; 664: 665: bSuccess = FALSE ; 666: ReleaseSemaphore ( ghSemaphore, // Let next waiting 667: 1, // reader in the queue 668: NULL ) ; 669: } 670: 671: break ; 672: 673: case WAIT_TIMEOUT: 674: DebugMsg ( "ReadDataBase: Error WAIT_TIMEOUT ghSemaphore\n" ) ; 675: 676: //where to put this? 677: cReadQueue-- ; // Reader leaving queue 678: /* 679: * Signal Writer if no Reader waiting 680: * 681: */ 682: if ( !cReadQueue ) 683: bSuccess = SetEvent ( ghWriteEvent1 ) ; 684: 685: bSuccess = FALSE ; 686: break ; 687: 688: case WAIT_ERROR: 689: ErrorMsg ( "ReadDataBase: Error WAIT_ERROR ghSemaphore" ) ; 690: 691: //where to put this? 692: cReadQueue-- ; // Reader leaving queue 693: /* 694: * Signal Writer if no Reader waiting 695: * 696: */ 697: if ( !cReadQueue ) 698: bSuccess = SetEvent ( ghWriteEvent1 ) ; 699: 700: bSuccess = FALSE ; 701: break ; 702: 703: default: 704: DebugMsg ( "ReadDataBase: Dropped through switch\n" ) ; 705: 706: //where to put this? 707: cReadQueue-- ; // Reader leaving queue 708: /* 709: * Signal Writer if no Reader waiting 710: * 711: */ 712: if ( !cReadQueue ) 713: bSuccess = SetEvent ( ghWriteEvent1 ) ; 714: 715: bSuccess = FALSE ; 716: break ; 717: } 718: } // END IF 719: 720: 721: 722: return ( bSuccess ) ; 723: } 724: 725: 726: 727: 728: 729: /***************************************************************************\ 730: ** ** 731: ** FUNCTION: WriteDataBase ( PSZ ** 732: ** ** 733: ** PURPOSE: Puts data into the database ** 734: ** ** 735: ** INPUT: Pointer to data ** 736: ** ** 737: ** OUTPUT: None ** 738: ** ** 739: ** ERROR: Returns False if it can not complete the request ** 740: ** ** 741: ** COMMENTS: A writer can not enter the database if ** 742: ** ** 743: ** 1) A writer already is in the database ** 744: ** 2) Any readers are in the database ** 745: ** ** 746: ** All reader waiting at the end of a write operation ** 747: ** have priority over the next writer ** 748: ** ** 749: \****************************************************************************/ 750: 751: BOOL APIENTRY WriteDataBase ( PSZ psz1, PSZ psz2 ) 752: { 753: BOOL bSuccess ; 754: DWORD dwSuccess ; 755: UNREFERENCED_PARAMETER ( psz2 ) ; 756: 757: // DebugMsg ( "In WriteDataBase\n" ) ; 758: 759: cWriteQueue++ ; // Writer entering queue 760: dwSuccess = SIGNALED ; 761: 762: // should the same event be used twice ??? 763: 764: if ( cReadQueue ) // Block if Reader waiting 765: dwSuccess = WaitForSingleObject ( ghWriteEvent1, 0xFFFFFFFF ) ; 766: // dwSuccess = WaitForSingleObject ( ghWriteEvent1, 5000 ) ; 767: 768: if ( dwSuccess != SIGNALED ) 769: { 770: DebugMsg ( "WriteDataBase: Error Waiting for ghWriteEvent1\n" ) ; 771: bSuccess = FALSE ; 772: } 773: else 774: { 775: /* 776: * Only allow 1 writer at a time in the database 777: * 778: */ 779: switch ( WaitForSingleObject ( ghMutex, 0xFFFFFFFF ) ) { 780: // switch ( WaitForSingleObject ( ghMutex, 3000 ) ) { 781: case SIGNALED: 782: try { 783: InWrite = TRUE ; 784: cWriteQueue-- ; 785: 786: /* 787: * Signal Reader if any waiting 788: * 789: */ 790: if ( cReadQueueEx ) 791: bSuccess = SetEvent ( ghReadEvent1 ) ; 792: 793: // Writer leaving queue 794: if ( cRead ) // Block if Reader in database 795: dwSuccess = WaitForSingleObject ( ghWriteEvent2, 0xFFFFFFFF ) ; 796: // dwSuccess = WaitForSingleObject ( ghWriteEvent2, 1500 ) ; 797: 798: if ( dwSuccess == SIGNALED ) 799: { 800: bSuccess = PutData ( psz1 ) ; 801: InWrite = FALSE ; 802: /* 803: * Signal Reader when no Writer waiting 804: * 805: */ 806: bSuccess = SetEvent ( ghReadEvent2 ) ; 807: ReleaseMutex ( ghMutex ) ; // Let next waiting writer in the queue 808: } 809: else 810: { 811: bSuccess = FALSE ; 812: InWrite = FALSE ; 813: /* 814: * Signal Reader when no Writer waiting 815: * 816: */ 817: bSuccess = SetEvent ( ghReadEvent2 ) ; 818: DebugMsg ( "WriteDataBase: Error Waiting on ghWriteEvent2\n" ) ; 819: } 820: } 821: finally { 822: InWrite = FALSE ; 823: /* 824: * Signal Reader after leaving database 825: * 826: */ 827: bSuccess = SetEvent ( ghReadEvent2 ) ; 828: 829: /* 830: * Signal Reader if no Writer in queue 831: * 832: */ 833: if ( !cWriteQueue ) 834: bSuccess = SetEvent ( ghReadEvent1 ) ; 835: 836: bSuccess = FALSE ; 837: ReleaseMutex ( ghMutex ) ; 838: } 839: break ; 840: 841: case WAIT_TIMEOUT: 842: DebugMsg ( "WriteDataBase: Error WAIT_TIMEOUT ghMutex\n" ) ; 843: cWriteQueue-- ; 844: /* 845: * Signal Reader if no Writer waiting 846: * 847: */ 848: if ( !cWriteQueue ) 849: bSuccess = SetEvent ( ghReadEvent1 ) ; 850: 851: bSuccess = FALSE ; 852: break ; 853: 854: case WAIT_ABANDONED: 855: DebugMsg ( "WriteDataBase: Error WAIT_ABANDONED ghMutex\n" ) ; 856: cWriteQueue-- ; 857: /* 858: * Signal Reader if no Writer waiting 859: * 860: */ 861: if ( !cWriteQueue ) 862: bSuccess = SetEvent ( ghReadEvent1 ) ; 863: 864: bSuccess = FALSE ; 865: break ; 866: 867: case WAIT_ERROR: 868: ErrorMsg ( "WriteDataBase: Error WAIT_ERROR ghMutex" ) ; 869: cWriteQueue-- ; 870: /* 871: * Signal Reader if no Writer waiting 872: * 873: */ 874: if ( !cWriteQueue ) 875: bSuccess = SetEvent ( ghReadEvent1 ) ; 876: 877: bSuccess = FALSE ; 878: break ; 879: 880: default: 881: DebugMsg ( "WriteDataBase: Dropped through switch\n" ) ; 882: cWriteQueue-- ; 883: /* 884: * Signal Reader if no Writer waiting 885: * 886: */ 887: if ( !cWriteQueue ) 888: bSuccess = SetEvent ( ghReadEvent1 ) ; 889: 890: bSuccess = FALSE ; 891: break ; 892: } 893: } // END IF 894: 895: 896: if ( cReadQueue ) 897: bSuccess = SetEvent ( ghReadEvent1 ) ; // Signal Reader 898: else 899: bSuccess = SetEvent ( ghWriteEvent1 ) ; // Signal Writer 900: 901: return ( bSuccess ) ; 902: } 903: 904: 905: 906: BOOL GetData ( PSZ psz ) 907: { 908: static UINT i = 0 ; 909: 910: strcpy ( psz, DataBase[i++ % MAX] ) ; 911: return ( TRUE ) ; 912: } 913: 914: 915: BOOL PutData ( PSZ psz ) 916: { 917: static UINT i = 0 ; 918: 919: i++ ; 920: DataBase[i % MAX] = strdup ( psz ) ; 921: return ( TRUE ) ; 922: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.