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