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