|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.