Annotation of pmsdk/samples/comtalk/threads.c, revision 1.1.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.