|
|
1.1 ! root 1: /*==============================================================*\ ! 2: * Semaph.c - routines for demonstrating semaphore API. * ! 3: * * ! 4: * Created 1990, Microsoft, IBM Corp. * ! 5: *--------------------------------------------------------------* ! 6: * This module contains code to demonstrate the use of * ! 7: * semaphores to control access to a resource shared by * ! 8: * multiple threads. Event semaphores are used to signal a * ! 9: * thread is to give up a resource. A Mutex semaphore is used * ! 10: * to provide exclusive access to the resource. A mux * ! 11: * semaphore provides a method to check multiple event * ! 12: * semaphores. * ! 13: * * ! 14: * * ! 15: *--------------------------------------------------------------* ! 16: * * ! 17: * This source file contains the following functions: * ! 18: * * ! 19: * VOID SemError(PSZ,USHORT); * ! 20: * USHORT CreateAllSems(VOID); * ! 21: * VOID StartSemExample(VOID); * ! 22: * VOID ThreadConsumer(ULONG); * ! 23: * VOID SignalUserEvent(PUSHORT pfAutoMode); * ! 24: * USHORT SetAutoMode(VOID); * ! 25: * VOID RunAuto(VOID); * ! 26: * VOID StopSemaphore(VOID); * ! 27: * * ! 28: * * ! 29: \*==============================================================*/ ! 30: ! 31: /*--------------------------------------------------------------*\ ! 32: * Include files, macros, defined constants, and externs * ! 33: \*--------------------------------------------------------------*/ ! 34: ! 35: #define LINT_ARGS ! 36: #define INCL_PM ! 37: #define INCL_BASE ! 38: ! 39: #include <os2.h> ! 40: #include <stdio.h> ! 41: #include <string.h> ! 42: #include <stdlib.h> ! 43: #include <dos.h> ! 44: #include "sem_pnt.h" ! 45: #include "semaph.h" ! 46: #include "sem_main.h" ! 47: #include "sem_dlg.h" ! 48: #include "sem_xtrn.h" ! 49: ! 50: #define STACKSIZE 0X10000L ! 51: #define TIMEOUTPERIOD 33L ! 52: #define EVENTSEM 0 ! 53: #define STOPSEM -1 ! 54: #define BASETEN 10 ! 55: ! 56: /*--------------------------------------------------------------*\ ! 57: * Global variables * ! 58: \*--------------------------------------------------------------*/ ! 59: ! 60: ! 61: /* Global variables for semaphore handles. Used only in this file. */ ! 62: ! 63: HEV hevStop, hevStopAuto, hevItem; ! 64: HMTX hmtxOwnResource; ! 65: HMUX hmuxResource; //, hmuxReady; ! 66: ! 67: /* Global variables for number of consumer threads & thread ID's */ ! 68: ! 69: USHORT usConsumerThreadsCreated; ! 70: TID tidAutoThread; ! 71: THRDATA thrConsumers[MAXUSERS]; ! 72: ULONG ulTimeout = TIMEOUTPERIOD; ! 73: ! 74: static VOID MyMove (USHORT usMyID, ULONG ulUser); ! 75: ! 76: /****************************************************************\ ! 77: * Procedure to print error messages to screen in a Message Box.* ! 78: *--------------------------------------------------------------* ! 79: * * ! 80: * Name: SemError(pszAPIName,usErrorCode) * ! 81: * * ! 82: * Purpose: Used to print name of API and error number when * ! 83: * a return code other than 0 is returned from an * ! 84: * API call. * ! 85: * * ! 86: * Usage: Called by all procedures in this file whenever * ! 87: * an API call fails. * ! 88: * * ! 89: * Method: The error number is converted to a string. String * ! 90: * functions are used to build the error message. * ! 91: * The message is printed in a Message Box. * ! 92: * * ! 93: * NOTE: This function is called by multiple threads, * ! 94: * therefore, only re-entrant functions can be used. * ! 95: * Note that string is build according to American * ! 96: * English conventions using hard-coded strings, and * ! 97: * so portability to other languages would require a * ! 98: * more flexible approach. * ! 99: * * ! 100: * Returns: none. * ! 101: * * ! 102: \****************************************************************/ ! 103: ! 104: ! 105: VOID SemError(PSZ pszAPIName,USHORT usErrorCode) ! 106: { ! 107: char acMessage[100],acErrorNumber[10]; ! 108: ! 109: itoa(usErrorCode,acErrorNumber,BASETEN); ! 110: strcpy(acMessage,pszAPIName); ! 111: strcat(acMessage,": error # "); ! 112: strcat(acMessage,acErrorNumber); ! 113: ! 114: WinMessageBox(HWND_DESKTOP, ! 115: hwndMain, ! 116: acMessage, ! 117: szAppName, ! 118: 1, ! 119: MB_OK); ! 120: } ! 121: ! 122: ! 123: /****************************************************************\ ! 124: * Routine to create semaphores used in this file. * ! 125: *--------------------------------------------------------------* ! 126: * * ! 127: * Name: CreateAllSems(VOID) * ! 128: * * ! 129: * Purpose: Create semaphores needed by the consumer threads. * ! 130: * Checks return codes from semaphore creation. * ! 131: * * ! 132: * Usage: Called by StartSemExample. * ! 133: * * ! 134: * Method: Semaphores are all anonymous private semaphores * ! 135: * since the semaphores are used by threads in the * ! 136: * same process. * ! 137: * * ! 138: * Returns: 0 if all semaphores are created successfully. * ! 139: * Otherwise returns error code for first create * ! 140: * semaphore API to fail. * ! 141: * * ! 142: \****************************************************************/ ! 143: ! 144: USHORT CreateAllSems(VOID) ! 145: { ! 146: USHORT rc; ! 147: SEMRECORD asr[MAXRESOURCES]; ! 148: INT i; ! 149: ! 150: rc = DosCreateMutexSem((PSZ)NULL,&hmtxOwnResource,NULL,FALSE); ! 151: if (rc) ! 152: { ! 153: SemError("DosCreateMutexSem",rc); ! 154: return(rc); ! 155: } ! 156: ! 157: for (i = 0; i < MAXRESOURCES; i++) { ! 158: if (rc = DosCreateEventSem((PSZ)NULL, &aSquares[i].hev, NULL, FALSE)) ! 159: { ! 160: SemError("DosCreateEventSem",rc); ! 161: return(rc); ! 162: } ! 163: else ! 164: { ! 165: asr[i].ulUser = i; ! 166: asr[i].hsemCur = (PVOID) aSquares[i].hev; ! 167: } ! 168: } ! 169: ! 170: /* this muxwait semaphore contains all of the event semaphores ! 171: * created in the loop above. ! 172: */ ! 173: if (rc = DosCreateMuxWaitSem((PSZ)NULL,&hmuxResource,MAXRESOURCES,asr, ! 174: DCMW_WAIT_ANY)) ! 175: { ! 176: SemError("DosCreateMuxWaitSem",rc); ! 177: return(rc); ! 178: } ! 179: if (rc = DosCreateEventSem((PSZ)NULL,&hevStop,NULL,FALSE)) ! 180: { ! 181: SemError("DosCreateEventSem",rc); ! 182: return(rc); ! 183: } ! 184: return(rc); ! 185: } ! 186: ! 187: /****************************************************************\ ! 188: * Routine to start semaphore example * ! 189: *--------------------------------------------------------------* ! 190: * * ! 191: * Name: StartSemExample(VOID) * ! 192: * * ! 193: * Purpose: Calls routines to create semaphores and draw * ! 194: * resources. Creates consumer threads. * ! 195: * * ! 196: * Usage: Called in file usercmd.c when the user selects * ! 197: * start from the semaphore menu. * ! 198: * * ! 199: * Method: Uses routines in paint.c to draw consumers and * ! 200: * resources. This is done by creating a paint * ! 201: * message, not calling the draw routines directly. * ! 202: * * ! 203: * Returns: TRUE if start succeeds, FALSE if start fails * ! 204: * * ! 205: \****************************************************************/ ! 206: ! 207: INT StartSemExample(VOID) ! 208: { ! 209: TID tid; ! 210: USHORT rc; ! 211: INT i; ! 212: FONTMETRICS fntmet; ! 213: HPS hps; ! 214: SWP swp; ! 215: ! 216: InitSemaphExample(); ! 217: ! 218: rc = CreateAllSems(); ! 219: ! 220: if (rc) ! 221: return FALSE; ! 222: ! 223: /* Create consumer threads. Note that values can be passed to ! 224: * threads in OS/2 2.0. We pass the ordinal number of the child ! 225: * to each child. ! 226: */ ! 227: ! 228: for (usConsumerThreadsCreated = 0; ! 229: usConsumerThreadsCreated < cNumUsers; usConsumerThreadsCreated++) ! 230: { ! 231: rc = DosCreateThread(&tid,ThreadConsumer,usConsumerThreadsCreated,1, ! 232: STACKSIZE); ! 233: if (rc) ! 234: { ! 235: SemError("DosCreateThread",rc); ! 236: return FALSE; ! 237: } ! 238: else ! 239: { ! 240: thrConsumers[usConsumerThreadsCreated].tid = tid; ! 241: thrConsumers[usConsumerThreadsCreated].lHits = 0L; ! 242: } ! 243: } ! 244: ! 245: for (i = 0; i < cNumUsers; i++) { ! 246: DosResumeThread (thrConsumers[i].tid); ! 247: } ! 248: ! 249: if (hps = WinGetPS (hwndMain)) ! 250: { ! 251: GpiQueryFontMetrics (hps, (LONG) sizeof fntmet, &fntmet); ! 252: WinQueryWindowPos (hwndMain, &swp); ! 253: SetRectPositions((SHORT)swp.cx, (SHORT)swp.cy, (SHORT) fntmet.lMaxBaselineExt, (SHORT) fntmet.lMaxDescender); ! 254: DrawRects (hps); ! 255: WinReleasePS (hps); ! 256: } ! 257: return TRUE; ! 258: } ! 259: ! 260: ! 261: /****************************************************************\ ! 262: * Routine to signal consumer to release resource. * ! 263: *--------------------------------------------------------------* ! 264: * * ! 265: * Name: SignalUserEvent(pfAutoMode) * ! 266: * * ! 267: * Purpose: Posts user event semaphore to signal thread to * ! 268: * release resource. Also posts event to stop * ! 269: * Auto mode if *pfAutoMode is true. * ! 270: * * ! 271: * Usage: Called in file usercmd.c when the user selects * ! 272: * Event from the semaphore menu. * ! 273: * * ! 274: * Method: Turns off Auto mode, if present by posting auto * ! 275: * semaphore. User event is then posted. * ! 276: * * ! 277: * Returns: * ! 278: * * ! 279: \****************************************************************/ ! 280: ! 281: VOID SignalUserEvent(PUSHORT pfAutoMode) ! 282: { ! 283: USHORT rc; ! 284: ! 285: /* If sample is in auto mode turn auto mode off. */ ! 286: ! 287: if (*pfAutoMode) ! 288: { ! 289: rc = DosPostEventSem(hevStopAuto); ! 290: if (rc) ! 291: { ! 292: SemError("DosPostEventSem Stop Auto",rc); ! 293: } ! 294: /* Wait for auto mode thread to die, so we don't end up with multiple * ! 295: * copies of it later. */ ! 296: ! 297: rc = DosWaitThread(&tidAutoThread,0L); ! 298: if (rc) ! 299: { ! 300: SemError("DosWaitThread",rc); ! 301: } ! 302: *pfAutoMode = FALSE; ! 303: DosCloseEventSem (hevStopAuto); ! 304: } ! 305: ! 306: /* If Auto mode haas already posted the event this is OK ! 307: so we will not check error codes here. */ ! 308: ! 309: DosPostEventSem(aSquares[rand() % MAXRESOURCES].hev); ! 310: } ! 311: ! 312: ! 313: /****************************************************************\ ! 314: * Routine to start Auto mode. * ! 315: *--------------------------------------------------------------* ! 316: * * ! 317: * Name: SetAutoMode(VOID) * ! 318: * * ! 319: * Purpose: Creates thread and semaphore needed to run auto * ! 320: * mode. * ! 321: * * ! 322: * Usage: Called in file usercmd.c when the user selects * ! 323: * Auto from the semaphore menu. * ! 324: * * ! 325: * Returns: NO_ERROR on success, else error from api call. * ! 326: * * ! 327: \****************************************************************/ ! 328: ! 329: USHORT SetAutoMode() ! 330: { ! 331: USHORT rc; ! 332: ! 333: rc = DosCreateEventSem((PSZ)NULL,&hevStopAuto,NULL,FALSE); ! 334: if (rc) ! 335: { ! 336: SemError("DosCreateEventSem",rc); ! 337: return(rc); ! 338: } ! 339: ! 340: rc = DosCreateThread(&tidAutoThread,RunAuto,0L,0L,STACKSIZE); ! 341: if (rc) ! 342: { ! 343: DosCloseEventSem (hevStopAuto); /* close semaphore created above */ ! 344: SemError("DosCreateThread",rc); ! 345: return(rc); ! 346: } ! 347: ! 348: return(NO_ERROR); ! 349: } ! 350: ! 351: ! 352: /****************************************************************\ ! 353: * Routine to run Auto mode. * ! 354: *--------------------------------------------------------------* ! 355: * * ! 356: * Name: RunAuto(VOID) * ! 357: * * ! 358: * Purpose: Posts user event at fixed time interval to signal * ! 359: * consumers to release resource. * ! 360: * * ! 361: * Usage: Thread created by SetAutoMode. * ! 362: * * ! 363: * Method: Kills itself when StopAutoMode semaphore is * ! 364: * posted. * ! 365: * * ! 366: * Returns: * ! 367: * * ! 368: \****************************************************************/ ! 369: ! 370: VOID RunAuto(VOID) ! 371: { ! 372: USHORT rcWait; ! 373: HAB habLocal; ! 374: HMQ hmqLocal; ! 375: INT i; ! 376: ! 377: /* Need a message queue for any thread that wants to print messages. */ ! 378: ! 379: habLocal = WinInitialize(NULL); ! 380: hmqLocal = WinCreateMsgQueue(habLocal,NULL); ! 381: ! 382: /* while stop auto semaphore not posted, post user event semaphore. */ ! 383: ! 384: /* Don't check return code from DosPostEventSem(hevUserEvent) ! 385: since we just want the resource to change hands. We don't ! 386: care if it changes hands exactly every time it goes through ! 387: the loop. ! 388: ! 389: The event may already be posted if the system is busy and ! 390: the resource threads don't finish with it fast enough. ! 391: This is not a problem in this case. ! 392: */ ! 393: ! 394: do { ! 395: /* if ulTimeout is zero, still waitevent for 1 msec to ! 396: * force yielding of CPU. ! 397: */ ! 398: rcWait = DosWaitEventSem(hevStopAuto, max (ulTimeout, 1)); ! 399: if (rcWait == ERROR_TIMEOUT) { ! 400: i = rand () % MAXRESOURCES; /* generate it */ ! 401: DosPostEventSem (aSquares[i].hev); ! 402: } ! 403: } while (rcWait == ERROR_TIMEOUT); ! 404: ! 405: /* If there was an error, print a message */ ! 406: ! 407: if (rcWait) { ! 408: SemError("DosWaitEventSem",rcWait); ! 409: } ! 410: ! 411: WinDestroyMsgQueue (hmqLocal); ! 412: WinTerminate (habLocal); ! 413: DosExit(EXIT_THREAD,0); ! 414: } ! 415: ! 416: ! 417: /**************************************************************** ! 418: * Routine to stop semaphore example. ! 419: *--------------------------------------------------------------- ! 420: * ! 421: * Name: BeginStop(pfAutoMode) ! 422: * ! 423: * Purpose: Posts stop event semaphore to signal threads to ! 424: * die. Also posts event to stop Auto mode if ! 425: * necessary. Then waits for threads to complete, ! 426: * Creates thread StopSemaphore which posts stop event ! 427: * and waits for child threads. ! 428: * ! 429: * Usage: Called in file usercmd.c when the user selects ! 430: * Stop from the semaphore menu. ! 431: * ! 432: * Method: Execs thread to do waits so that message thread ! 433: * doesn't hang. ! 434: * Returns: ! 435: * ! 436: \****************************************************************/ ! 437: VOID ! 438: BeginStop (PUSHORT pfAutoMode) ! 439: { ! 440: USHORT rc; ! 441: TID tidLocal; ! 442: ! 443: rc = DosPostEventSem(hevStop); ! 444: if (rc) ! 445: { ! 446: SemError("DosPostEventSem",rc); ! 447: return; ! 448: } ! 449: ! 450: if (*pfAutoMode) ! 451: { ! 452: rc = DosPostEventSem(hevStopAuto); ! 453: if (rc) ! 454: { ! 455: SemError("DosPostEventSem",rc); ! 456: } ! 457: } ! 458: ! 459: rc = DosCreateThread(&tidLocal,StopSemaphore,(LONG)pfAutoMode,0,STACKSIZE); ! 460: if (rc) ! 461: { ! 462: SemError("DosCreateThread",rc); ! 463: } ! 464: } ! 465: ! 466: /**************************************************************** ! 467: * Routine to really stop semaphore example. ! 468: *--------------------------------------------------------------- ! 469: * ! 470: * Name: StopSemaphore(pfAutoMode) ! 471: * ! 472: * Purpose: Waits for threads to complete, ! 473: * Sends message to message thread to indicate this ! 474: * has occurred, and exits. ! 475: * ! 476: * Usage: Exec'd from BeginStop when user selects Stop from ! 477: * Semaphore menu. ! 478: * ! 479: * Method: Turns off Auto mode, if present by posting auto ! 480: * semaphore. Then stop event is posted. Waits ! 481: * for threads to die. ! 482: * Returns: ! 483: * ! 484: \****************************************************************/ ! 485: ! 486: ! 487: VOID StopSemaphore(PUSHORT pfAutoMode) ! 488: { ! 489: USHORT rc,usCount, i; ! 490: ! 491: ! 492: if (*pfAutoMode) ! 493: { ! 494: rc = DosWaitThread(&tidAutoThread,0L); ! 495: if (rc && (rc != ERROR_INVALID_THREADID)) ! 496: { ! 497: SemError("DosWaitThread",rc); ! 498: } ! 499: *pfAutoMode = FALSE; ! 500: } ! 501: ! 502: ! 503: /* Wait for usConsumer threads to die. Order of death not important. */ ! 504: ! 505: for (usCount = 0; usCount < usConsumerThreadsCreated; usCount++) ! 506: { ! 507: rc = DosWaitThread(&thrConsumers[usCount].tid,0L); ! 508: ! 509: /* rc is ERROR_INVALID_THREADID the thread is already dead. This *\ ! 510: \* is OK and not a error. */ ! 511: ! 512: if (rc && (rc != ERROR_INVALID_THREADID)) ! 513: { ! 514: SemError("DosWaitThread",rc); ! 515: } ! 516: } ! 517: ! 518: /* Threads dead so we don't need semaphores any more. */ ! 519: ! 520: DosCloseEventSem(hevStopAuto); ! 521: DosCloseEventSem(hevStop); ! 522: DosCloseMutexSem(hmtxOwnResource); ! 523: for (i = 0; i < MAXRESOURCES; i++) { ! 524: DosCloseEventSem(aSquares[i].hev); ! 525: } ! 526: DosCloseMuxWaitSem (hmuxResource ); ! 527: WinPostMsg (hwndMain, WM_COMMAND, (MPARAM)IDM_STOPFINISHED, (MPARAM)NULL); ! 528: DosExit (EXIT_THREAD, 0); ! 529: } ! 530: ! 531: /****************************************************************\ ! 532: * Routine for consumer threads. * ! 533: *--------------------------------------------------------------* ! 534: * * ! 535: * Name: ThreadConsumer(ULONG) * ! 536: * * ! 537: * Purpose: There are NUMUSERS copies of this thread to act * ! 538: * as consumers of the resource. The thread waits * ! 539: * for exclusive access to the resource and colors it* ! 540: * * ! 541: * Usage: Threads created by StartSemExample. * ! 542: * * ! 543: * Method: Waits for mutex to gain ownership of resource. * ! 544: * Releases resource when user event. Dies when * ! 545: * Stop event. * ! 546: * Returns: * ! 547: * * ! 548: \****************************************************************/ ! 549: ! 550: VOID ThreadConsumer(USHORT usMyID) ! 551: { ! 552: ULONG ulPostCnt; ! 553: ULONG ulUser; ! 554: USHORT rc; ! 555: HAB hab; ! 556: HMQ hmq; ! 557: ! 558: /* Need a message queue for any thread that wants to print messages. */ ! 559: hab = WinInitialize(NULL); ! 560: hmq = WinCreateMsgQueue(hab,NULL); ! 561: ! 562: /* while the user has not selected stop ... */ ! 563: while ((DosWaitEventSem(hevStop,SEM_IMMEDIATE_RETURN)) == ERROR_TIMEOUT) { ! 564: /* Wait for exclusive ownership of resource */ ! 565: ! 566: DosRequestMutexSem(hmtxOwnResource,SEM_INDEFINITE_WAIT); ! 567: ! 568: /* the following check is necessary because the stop semaphore ! 569: * may have been posted while we were waiting on the mutex ! 570: */ ! 571: if (DosWaitEventSem(hevStop, SEM_IMMEDIATE_RETURN) == ERROR_TIMEOUT) { ! 572: /* an item is ready, which one? ! 573: * don't wait forever because there is ! 574: * a possibility that the stop semaphore ! 575: * was posted and that no more resource ! 576: * is forthcoming. we wait twice as long ! 577: * as we think is necessary. ! 578: */ ! 579: if (!DosWaitMuxWaitSem (hmuxResource, max (ulTimeout << 1, TIMEOUTPERIOD), &ulUser)) { ! 580: MyMove (usMyID, ulUser); ! 581: DosResetEventSem(aSquares[ulUser].hev, &ulPostCnt); ! 582: } ! 583: } ! 584: ! 585: /*Let some other thread have resource. */ ! 586: if (rc = DosReleaseMutexSem(hmtxOwnResource)) { ! 587: SemError("DosReleaseMutexSem",rc); ! 588: } ! 589: } ! 590: ! 591: /* hevStop was posted, kill this thread */ ! 592: WinDestroyMsgQueue (hmq); ! 593: WinTerminate (hab); ! 594: DosExit(EXIT_THREAD,0); ! 595: } ! 596: ! 597: ! 598: /****************************************************************\ ! 599: * called from ThreadConsumer to make and register move ! 600: *-------------------------------------------------------------- ! 601: * ! 602: * Name: MyMove (usMyID, ulUser) ! 603: * USHORT usMyID; id of caller ! 604: * ULONG ulUser; number of the square to "hit" ! 605: * ! 606: * Purpose: color a square on the game board 'my' color. ! 607: * update display of number of hits for 'my' thread. ! 608: * ! 609: * Usage: called only from ThreadConsumer ! 610: * ! 611: * Method: ! 612: * ! 613: * Returns: none ! 614: * ! 615: \****************************************************************/ ! 616: static VOID ! 617: MyMove (USHORT usMyID, ULONG ulUser) ! 618: { ! 619: if (aSquares [ulUser].usOwner != usMyID) { ! 620: aSquares[ulUser].usOwner = usMyID; ! 621: thrConsumers[usMyID].lHits++; ! 622: DrawResource (&aSquares[ulUser].rcl, colors [usMyID]); ! 623: DrawStats (usMyID); ! 624: } ! 625: } ! 626: ! 627: ! 628: /****************************************************************\ ! 629: * Routine to init game board * ! 630: *--------------------------------------------------------------* ! 631: * * ! 632: * Name: InitSemaphExample(VOID) * ! 633: * * ! 634: * Purpose: Initializes game board unowned, sets semaphores * ! 635: * to 0. * ! 636: * Usage: Called from StartSemExample in semaph.c when * ! 637: * user selects start from the semaphore menu. * ! 638: * Method: * ! 639: * * ! 640: * Returns: none * ! 641: * * ! 642: \****************************************************************/ ! 643: VOID InitSemaphExample(VOID) ! 644: { ! 645: int i; ! 646: ! 647: for (i = 0; i < MAXRESOURCES; i++) { ! 648: aSquares[i].hev = 0; ! 649: aSquares[i].usOwner = UNOWNED; ! 650: } ! 651: hevStopAuto = 0L; ! 652: hevStop = 0L; ! 653: hmtxOwnResource = 0L; ! 654: hmuxResource = 0L; ! 655: } ! 656:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.