|
|
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.