Annotation of pmsdk/samples/comtalk/threads.c, revision 1.1

1.1     ! root        1: /*
        !             2:     threads.c -- Supplementary threads module
        !             3:     Created by Microsoft Corporation, 1989
        !             4: */
        !             5: #define        INCL_DOSSEMAPHORES
        !             6: #define                INCL_DOSMEMMGR
        !             7: #define                INCL_DOSPROCESS
        !             8: #define                INCL_WINMESSAGEMGR
        !             9: #define                INCL_WINTRACKRECT
        !            10: #include       <os2.h>
        !            11: #include       "global.h"
        !            12: #include       "avio.h"
        !            13: #include       "circleq.h"
        !            14: #include       "comport.h"
        !            15: #include       "threads.h"
        !            16: #include       "malloc.h"
        !            17: 
        !            18: int            rc;
        !            19: HWND           hWndMaster;
        !            20: BOOL           fNoUpdate = TRUE;
        !            21: BOOL           fWrap;
        !            22: /*
        !            23:     Declare pointers to stacks
        !            24: */
        !            25: PINT           pStackWPT,
        !            26:                pStackRPT,
        !            27:                pStackWST;
        !            28: /*
        !            29:     ...Selectors
        !            30: */
        !            31: SEL            selStackWPT,
        !            32:                selStackRPT,
        !            33:                selStackWST;
        !            34: /*
        !            35:     ...Thread ID numbers
        !            36: */
        !            37: TID            tidWPT,
        !            38:                tidRPT,
        !            39:                tidWST;
        !            40: /*
        !            41:     ...Control booleans, semaphores
        !            42: */
        !            43: BOOL           fBreak,                 /* Break active */
        !            44:                fAlive;                 /* Should the threads be killed? */
        !            45: LONG           lSemLock,               /* TypeAhead buffer locks... */
        !            46:                lSemEmpty,
        !            47:                lSemFull,
        !            48:                lSemOverflow;           /* Buffer overflow semaphore */
        !            49: CHAR           TypeAhead[BUFSIZE];     /* TypeAhead buffer and controls */
        !            50: int            nBufLoc, nChars;
        !            51: LineInfo       aliReadAhead[RASIZE];
        !            52: int            cliReadAhead;
        !            53: LONG           lSemRALock;
        !            54: LONG           lSemRAFull;
        !            55: LONG           lSemRAEmpty;
        !            56: /*
        !            57:     Messages....
        !            58: */
        !            59: char aszMessage[MBE_NUMMSGS][MAXLINELEN] = {
        !            60:     "Error opening port",
        !            61:     "Error writing port",
        !            62:     "Error reading port",
        !            63:     "Circular buffer overflowing"
        !            64: };
        !            65: /*
        !            66:     Macros
        !            67: */
        !            68: #define        NOUPDATE                (MRESULT) FALSE
        !            69: #define        UPDATE                  (MRESULT) TRUE
        !            70: #define        ThdBufNextLoc(n)        (n = ((n + 1) % BUFSIZE))
        !            71: #define        ThdBufLastLoc(n)        (n = (n > 0) ? (n - 1) : (BUFSIZE - 1))
        !            72: #define        ThdNextRALoc(n)         (n = ((n + 1) % RASIZE))
        !            73: #define MessageBox(s, v)       WinPostMsg(hWndMaster, WM_MSGBOX, s, v)
        !            74: /*
        !            75:     Local routines
        !            76: */
        !            77: void far WritePortThread(void);
        !            78: void far ReadPortThread(void);
        !            79: void far WriteScreenThread(void);
        !            80: void Process(Line, Line, int far *);
        !            81: 
        !            82: int ThdCreate(PFNTHREAD Routine, PBYTE *pStack, SEL *selStack, TID *tidThread) {
        !            83: /*
        !            84:     Initialize the thread
        !            85: */
        !            86:     if (rc = DosAllocSeg(sizeof(int) * STACKSIZE, selStack, 0)) return rc;
        !            87:     *pStack = (PBYTE) MAKEP(*selStack, 0) + STACKSIZE;
        !            88:     return (rc = DosCreateThread(Routine, tidThread, *pStack));
        !            89: }
        !            90: 
        !            91: void ThdInitialize(HWND hWnd, COM Term) {
        !            92: /*
        !            93:     Initialize Booleans, Master Window
        !            94: */
        !            95:     fBreak = FALSE;
        !            96:     fAlive = TRUE;
        !            97:     hWndMaster = hWnd;
        !            98: /*
        !            99:     Initialize TypeAhead buffer
        !           100: */
        !           101:     nBufLoc = -1;
        !           102:     nChars = 0;
        !           103: /*
        !           104:     Initialize ReadAhead buffer
        !           105: */
        !           106:     cliReadAhead = 0;
        !           107: /*
        !           108:     Spawn off the threads
        !           109: */
        !           110:     rc = ThdCreate(WritePortThread,
        !           111:                   (PBYTE *) &pStackWPT, &selStackWPT, &tidWPT);
        !           112:     rc = ThdCreate(ReadPortThread,
        !           113:                   (PBYTE *) &pStackRPT, &selStackRPT, &tidRPT);
        !           114:     rc = ThdCreate(WriteScreenThread,
        !           115:                   (PBYTE *) &pStackWST, &selStackWST, &tidWST);
        !           116: /*
        !           117:     Open up the COM port and the circular queue
        !           118: */
        !           119:     if (rc = ComInit(Term))    { /* Initialize terminal */
        !           120:        MessageBox(MBE_OPENPORT, NOUPDATE);
        !           121:     } 
        !           122:     fWrap = Term.fWrap;
        !           123: }
        !           124: 
        !           125: void ThdTerminate(void) {
        !           126: /*
        !           127:     Kill the threads (maybe time delayed) and clean up.
        !           128:     Yes, I throw away the return codes.
        !           129: 
        !           130:     Problem:  The ReadPort thread might not die, because it blocks
        !           131:     waiting for a character to be read.
        !           132: */
        !           133:     if (fAlive) {
        !           134:        fAlive = FALSE;                 /* Kill thread loops            */
        !           135:        if (fBreak) rc = ComUnbreak();  /* Remove break signal          */
        !           136:        rc = ComClose();                /* Close the port               */
        !           137:        DosSemClear(&lSemEmpty);        /* Make WritePort unblock       */
        !           138:        DosSemClear(&lSemRAFull);       /* Make ReadPort unblock        */
        !           139:        DosSemClear(&lSemRAEmpty);      /* Make WriteScreen unblock     */
        !           140:     }
        !           141: }
        !           142: 
        !           143: void ThdDoBreak(void) {
        !           144: /*
        !           145:     Try to send break for a second
        !           146: */
        !           147:     ComBreak();
        !           148:     DosSleep(1000L);
        !           149:     ComUnbreak();
        !           150: }
        !           151: 
        !           152: int ThdPutChar(char ch) {
        !           153: /*
        !           154:     Perhaps we will enter an entire key packet
        !           155:     But we can't really block, because we gotta respond.
        !           156:     Solution:  This time, we time out.
        !           157: */
        !           158: /*
        !           159:     Manipulate the typeahead buffer (circular queue)
        !           160: */
        !           161:     if (nChars >= BUFSIZE) {           /* Block if buffer full */
        !           162:        DosSemSet(&lSemFull);
        !           163:        /*
        !           164:            Timeout possibility; probably want TIMEOUT < 1 second
        !           165:        */
        !           166:        if (rc = DosSemWait(&lSemFull, TIMEOUT)) return rc;
        !           167:     }
        !           168:     ThdBufNextLoc(nBufLoc);            /* Increments to next location */
        !           169:     /*
        !           170:        Be really impatient...
        !           171:        This protects the queue, but we should never read/write
        !           172:        the same queue location.  Maybe I'll move it out later.
        !           173:     */
        !           174:     if (rc = DosSemRequest(&lSemLock, TIMEOUT)) { /* Another quick timeout */
        !           175:        ThdBufLastLoc(nBufLoc);
        !           176:        return rc;
        !           177:     }
        !           178:     TypeAhead[nBufLoc] = ch; 
        !           179:     nChars++;
        !           180:     DosSemClear(&lSemEmpty);
        !           181:     DosSemClear(&lSemLock);
        !           182:     return 0;
        !           183: }
        !           184: 
        !           185: void far WritePortThread(void) {
        !           186: /*
        !           187:     The routine which writes your WM_CHARS to the port,
        !           188:     one at a time, nice and easy.  We can even wait all
        !           189:     day (and will, at the rate a user types....)
        !           190: 
        !           191:     The typeahead buffer is protected with semaphores,
        !           192:     although a move is probably an atomic operation;
        !           193:     also, it should be secure to read the element, without
        !           194:     having to protect the buffer.
        !           195: */
        !           196:     int MyLoc = -1;
        !           197:     char ch;
        !           198: 
        !           199:     while (fAlive) {
        !           200:        if (nChars < 1) {               /* Wait if the queue is empty */
        !           201:            DosSemSet(&lSemEmpty);
        !           202:            DosSemWait(&lSemEmpty, MAXTIMEOUT);
        !           203:        } else if (!(rc = DosSemRequest(&lSemLock, MAXTIMEOUT))) {
        !           204:            ThdBufNextLoc(MyLoc);
        !           205:            ch = TypeAhead[MyLoc];      /* writing to the port is slow, and */
        !           206:            nChars--;                   /* we want to release the semaphore */
        !           207:            DosSemClear(&lSemFull);
        !           208:            DosSemClear(&lSemLock);
        !           209:            if (rc = ComWrite(TypeAhead[MyLoc])) {
        !           210:                /* Post the message... */
        !           211:                MessageBox(MBE_WRITEPORT, NOUPDATE);
        !           212:            }
        !           213:        }
        !           214:     }
        !           215:     DosExit(EXIT_THREAD, 0);
        !           216: }
        !           217: 
        !           218: void far ReadPortThread(void) {
        !           219: /*
        !           220:     Read from the port, a line at a time
        !           221:     The semaphores force private queue access
        !           222: */
        !           223:     int iLine = 0;
        !           224: 
        !           225:     while (fAlive) {
        !           226:        if (cliReadAhead < RASIZE) {
        !           227:            if (ComRead(&aliReadAhead[iLine]))
        !           228:                MessageBox(MBE_COMREAD, (MPARAM) ComError());
        !           229:            else if (&aliReadAhead[iLine].cch) {
        !           230:                DosSemRequest(&lSemRALock, MAXTIMEOUT);
        !           231:                cliReadAhead++;
        !           232:                DosSemClear(&lSemRALock);
        !           233:                DosSemClear(&lSemRAEmpty);
        !           234:                ThdNextRALoc(iLine);
        !           235:            }
        !           236:        } else {
        !           237:            DosSemSet(&lSemRAFull);
        !           238:            DosSemWait(&lSemRAFull, TIMEOUT);
        !           239:        }
        !           240:     }
        !           241:     DosExit(EXIT_THREAD, 0);
        !           242: }
        !           243: 
        !           244: int ThdPutString(char a[], int n) {
        !           245:     int i, rc = 0;
        !           246: 
        !           247:     for (i = 0; i < n; i++)
        !           248:        if (!rc) rc = ThdPutChar(a[i]);
        !           249:     return rc;
        !           250: }
        !           251: 
        !           252: void Process(Line lCmd, Line lOutput, int far *pi) {
        !           253: /*
        !           254:     This routine filters characters from the port, before we
        !           255:     display them to the screen.
        !           256: 
        !           257:     To make this a full blown terminal emulator application,
        !           258:     all that's needed is to trap cursor movement sequences
        !           259:     here, and then to retrieve the appropriate queue line.
        !           260: */
        !           261:     USHORT usTemp;
        !           262:     int i;
        !           263: 
        !           264:     while ((lCmd->szText[*pi] != '\n') && ((*pi) < lCmd->cch)) {
        !           265:        switch (lCmd->szText[*pi]) {
        !           266:            case '\b':
        !           267:                if (lOutput->cch > 0) lOutput->cch--;
        !           268:                break;
        !           269:            case '\r':
        !           270:            case '\0':
        !           271:                break;
        !           272:            case '\007':        /* Ctrl G */
        !           273:                WinAlarm(HWND_DESKTOP, WA_NOTE);
        !           274:                break;
        !           275:            case '\t':
        !           276:                if ((usTemp = (((lOutput->cch >> 3) + 1) << 3)) < MAXLINELEN) {
        !           277:                    for (i = lOutput->cch; i < usTemp; i++)
        !           278:                        lOutput->szText[i] = ' ';
        !           279:                    lOutput->cch = usTemp;
        !           280:                }
        !           281:                break;
        !           282:            default:
        !           283:                if (fWrap) {
        !           284:                    if (lOutput->cch >= MAXLINELEN) {
        !           285:                        lOutput->fComplete = TRUE;
        !           286:                        lOutput->fDrawn = FALSE;
        !           287:                        return;
        !           288:                    } else lOutput->szText[lOutput->cch++] = lCmd->szText[*pi];
        !           289:                } else {
        !           290:                    if (lOutput->cch < MAXLINELEN) /* Straight nowrap */
        !           291:                        lOutput->szText[lOutput->cch++] = lCmd->szText[*pi];
        !           292:                }
        !           293:                break;
        !           294:        }
        !           295:        (*pi)++;
        !           296:     }
        !           297:     /*
        !           298:        Complete line if it doesn't exhaust the command string, and
        !           299:        ends with a newline (\n).  If so, increment string length, but
        !           300:        don't write (potentially) out of the array bounds.
        !           301:     */
        !           302:     if (lOutput->fComplete =
        !           303:                (((*pi) < lCmd->cch) && (lCmd->szText[*pi] == '\n')))
        !           304:        (*pi)++;
        !           305: 
        !           306:     lOutput->fDrawn = FALSE;
        !           307: }
        !           308: 
        !           309: void ThdReset(void) {
        !           310:     DosSemClear(&lSemOverflow);
        !           311: }
        !           312: 
        !           313: void far WriteScreenThread(void) {
        !           314:     int                iLine = 0;
        !           315:     LineInfo   liQueueEntry;
        !           316:     int                iLinePos = 0;
        !           317:     BOOL       fMore = FALSE;
        !           318: 
        !           319:     liQueueEntry.cch = 0;
        !           320:     while (fAlive) {
        !           321:        if ((cliReadAhead > 0) || fMore) {
        !           322:            Process(&aliReadAhead[iLine], &liQueueEntry, &iLinePos);
        !           323:            /*
        !           324:                Add the entry to the queue if it's:
        !           325:                    1) A complete line
        !           326:                    2) There's nothing more to read
        !           327:            */
        !           328:            if (liQueueEntry.fComplete || (cliReadAhead <= 1)) {
        !           329:                while (!QueInsertLine(&liQueueEntry)) {
        !           330:                    MessageBox(MBE_QUEUEFULL, UPDATE);
        !           331:                    DosSemSet(&lSemOverflow);
        !           332:                    DosSemWait(&lSemOverflow, MAXTIMEOUT);
        !           333:                }
        !           334:                /*
        !           335:                    If complete line is read, reset line pointer
        !           336:                */
        !           337:                if (liQueueEntry.fComplete) {
        !           338:                    liQueueEntry.cch = 0;
        !           339:                    /*
        !           340:                        If done moving, move cursor to the right place.
        !           341:                        (the beginning of the next line), so that the
        !           342:                        user knows when they've hit <Enter>.
        !           343:                    */
        !           344:                    if (cliReadAhead <= 1) {
        !           345:                        liQueueEntry.fComplete = liQueueEntry.fDrawn = FALSE;
        !           346:                        while (!QueInsertLine(&liQueueEntry)) {
        !           347:                            MessageBox(MBE_QUEUEFULL, UPDATE);
        !           348:                            DosSemSet(&lSemOverflow);
        !           349:                            DosSemWait(&lSemOverflow, MAXTIMEOUT);
        !           350:                        }
        !           351:                    }
        !           352:                }
        !           353:            }
        !           354:            /*
        !           355:                If there's no more to process, bump the read pointer
        !           356:                and possibly unblock the Read Port thread
        !           357:            */
        !           358:            if (!(fMore = (iLinePos < aliReadAhead[iLine].cch))) {
        !           359:                ThdNextRALoc(iLine);
        !           360:                iLinePos = 0;
        !           361:                DosSemRequest(&lSemRALock, MAXTIMEOUT);
        !           362:                cliReadAhead--;
        !           363:                DosSemClear(&lSemRALock);
        !           364:                DosSemClear(&lSemRAFull);
        !           365:            }
        !           366:        } else {
        !           367:            if (fNoUpdate) {
        !           368:                fNoUpdate = WinPostMsg(hWndMaster, WM_AVIOUPDATE, NULL, NULL);
        !           369:            }
        !           370:            DosSemSet(&lSemRAEmpty);
        !           371:            DosSemWait(&lSemRAEmpty, TIMEOUT);
        !           372:        }
        !           373:     }
        !           374:     DosExit(EXIT_THREAD, 0);
        !           375: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.