|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* ! 25: * ioThread.m - I/O thread example. ! 26: * ! 27: * This example consists of a simple driver class with one I/O thread. ! 28: * Exported methods are invoked interactively via stdin. These methods ! 29: * pass commands to the I/O thread, which performs various trivial tasks ! 30: * and then notifies the exported methods of command complete. ! 31: */ ! 32: ! 33: #include "ioThread.h" ! 34: #include "ioThreadPrivate.h" ! 35: ! 36: static void MyDeviceThread(id deviceId); ! 37: ! 38: /* ! 39: * A regular old Unix-y program to exercise the MyDevice class. ! 40: */ ! 41: int main(int argc, char **argv) ! 42: { ! 43: id devId; ! 44: char in_string[40]; ! 45: int aNumber; ! 46: ! 47: /* ! 48: * Create and initialize one instance of MyDevice. Forget devPort ! 49: * for this example. ! 50: */ ! 51: devId = [MyDevice alloc]; ! 52: [devId myDeviceInit]; ! 53: ! 54: /* ! 55: * Main I/O loop. We'll invoke the exported methods on myDevice ! 56: * per user input. ! 57: */ ! 58: ! 59: while(1) { ! 60: printf("Main Loop:\n"); ! 61: printf(" p print number\n"); ! 62: printf(" g get number\n"); ! 63: printf(" q quit program\n\n"); ! 64: printf("Enter Selection: "); ! 65: gets(in_string); ! 66: switch(in_string[0]) { ! 67: case 'p': ! 68: /* ! 69: * Get a number, pass it throught to MyDevice's ! 70: * I/O thread for display. ! 71: */ ! 72: printf("\nEnter number to pass to I/O thread: "); ! 73: gets(in_string); ! 74: aNumber = atoi(in_string); ! 75: [devId printNumber:aNumber]; ! 76: break; ! 77: ! 78: case 'g': ! 79: /* ! 80: * Get a number via MyDevice's I/O thread. ! 81: */ ! 82: aNumber = [devId getNumber]; ! 83: printf("getNumber returned %d\n", aNumber); ! 84: break; ! 85: ! 86: case 'q': ! 87: /* ! 88: * Shut down. ! 89: */ ! 90: [devId free]; ! 91: exit(0); ! 92: ! 93: default: ! 94: printf("**Illegal Selection\n"); ! 95: break; ! 96: } ! 97: } ! 98: ! 99: /* NOT REACHED */ ! 100: } ! 101: ! 102: /* ! 103: * Implementation of simple device. ! 104: */ ! 105: @implementation MyDevice ! 106: ! 107: /* ! 108: * Initialization. ! 109: */ ! 110: - myDeviceInit ! 111: { ! 112: /* ! 113: * Initialize instance variables. ! 114: */ ! 115: ioQueueLock = [NXConditionLock new]; ! 116: queue_init(&ioQueue); ! 117: ! 118: /* ! 119: * Start up the I/O thread. ! 120: */ ! 121: ioThread = IOForkThread((IOThreadFunc)MyDeviceThread, self); ! 122: ! 123: /* ! 124: * Register with IODevice-level code. ! 125: */ ! 126: [self setName:"myDevice"]; ! 127: [super init]; ! 128: [self registerDevice]; ! 129: return self; ! 130: } ! 131: ! 132: /* ! 133: * Run-time methods. ! 134: */ ! 135: ! 136: /* ! 137: * Have I/O thread get a number from user. ! 138: */ ! 139: - (int)getNumber ! 140: { ! 141: cmdBuf_t *cmdBuf; ! 142: int result; ! 143: ! 144: /* ! 145: * Set up a cmdBuf. ! 146: */ ! 147: cmdBuf = [self cmdBufAlloc]; ! 148: cmdBuf->cmd = IOC_GETNUM; ! 149: ! 150: /* ! 151: * Pass the cmdBuf to the I/O thread. On return, the desired ! 152: * number is in cmdBuf.aNumber. ! 153: */ ! 154: [self cmdBufExec:cmdBuf]; ! 155: result = cmdBuf->aNumber; ! 156: [self cmdBufFree:cmdBuf]; ! 157: return result; ! 158: } ! 159: ! 160: /* ! 161: * Have I/O thread print a number. ! 162: */ ! 163: - (void)printNumber : (int)aNumber ! 164: { ! 165: cmdBuf_t *cmdBuf; ! 166: ! 167: /* ! 168: * Set up a cmdBuf. ! 169: */ ! 170: cmdBuf = [self cmdBufAlloc]; ! 171: cmdBuf->cmd = IOC_PRINTNUM; ! 172: cmdBuf->aNumber = aNumber; ! 173: ! 174: /* ! 175: * Pass the cmdBuf to the I/O thread. ! 176: */ ! 177: [self cmdBufExec:cmdBuf]; ! 178: [self cmdBufFree:cmdBuf]; ! 179: return; ! 180: } ! 181: ! 182: /* ! 183: * Have I/O thread shut down cleanly. ! 184: */ ! 185: - free ! 186: { ! 187: cmdBuf_t *cmdBuf; ! 188: ! 189: /* ! 190: * Set up a cmdBuf. ! 191: */ ! 192: cmdBuf = [self cmdBufAlloc]; ! 193: cmdBuf->cmd = IOC_QUIT; ! 194: ! 195: /* ! 196: * Pass the cmdBuf to the I/O thread. ! 197: */ ! 198: [self cmdBufExec:cmdBuf]; ! 199: [self cmdBufFree:cmdBuf]; ! 200: ! 201: /* ! 202: * Free instance variables. ! 203: */ ! 204: [ioQueueLock free]; ! 205: ! 206: /* ! 207: * Have superclass take care of the rest. ! 208: */ ! 209: return [super free]; ! 210: } ! 211: ! 212: ! 213: /* ! 214: * Methods invoked by ioThread. ! 215: */ ! 216: ! 217: /* ! 218: * Wait for a work to appear in ioQueue. ! 219: */ ! 220: - (cmdBuf_t *)waitForCmdBuf ! 221: { ! 222: cmdBuf_t *cmdBuf; ! 223: ! 224: [ioQueueLock lockWhen:QUEUE_FULL]; ! 225: ! 226: /* ! 227: * At this point, we still hold ioQueueLock'. Remove ! 228: * the first element in ioQueue. ! 229: */ ! 230: cmdBuf = (cmdBuf_t *)queue_first(&ioQueue); ! 231: queue_remove(&ioQueue, ! 232: cmdBuf, ! 233: cmdBuf_t *, ! 234: link); ! 235: ! 236: /* ! 237: * Release ioQueueLock, updating its condition variable as ! 238: * appropriate, and return the new cmdBuf to the ioThread. ! 239: */ ! 240: if(queue_empty(&ioQueue)) ! 241: [ioQueueLock unlockWith:QUEUE_EMPTY]; ! 242: else ! 243: [ioQueueLock unlockWith:QUEUE_FULL]; ! 244: return cmdBuf; ! 245: } ! 246: ! 247: /* ! 248: * Notify client of I/O complete. ! 249: */ ! 250: - (void)cmdBufComplete : (cmdBuf_t *)cmdBuf ! 251: { ! 252: [cmdBuf->cmdLock lock]; ! 253: [cmdBuf->cmdLock unlockWith:CMD_COMPLETE]; ! 254: } ! 255: ! 256: @end ! 257: ! 258: ! 259: ! 260: /* ! 261: * Private methods. ! 262: */ ! 263: ! 264: @implementation MyDevice ( MyDevicePrivate ) ! 265: ! 266: /* ! 267: * Create and initialize a new cmdBuf_t. ! 268: */ ! 269: - (cmdBuf_t *)cmdBufAlloc ! 270: { ! 271: cmdBuf_t *cmdBuf; ! 272: ! 273: cmdBuf = IOMalloc(sizeof(cmdBuf_t)); ! 274: cmdBuf->cmdLock = [NXConditionLock new]; ! 275: [cmdBuf->cmdLock lock]; ! 276: [cmdBuf->cmdLock unlockWith:CMD_BUSY]; ! 277: return cmdBuf; ! 278: } ! 279: ! 280: /* ! 281: * Free a cmdBuf_t. ! 282: */ ! 283: - (void)cmdBufFree : (cmdBuf_t *)cmdBuf ! 284: { ! 285: [cmdBuf->cmdLock free]; ! 286: IOFree(cmdBuf, sizeof(cmdBuf_t)); ! 287: } ! 288: ! 289: /* ! 290: * Pass a cmdBuf to the I/O thread and wait for completion. ! 291: */ ! 292: - (void)cmdBufExec : (cmdBuf_t *)cmdBuf ! 293: { ! 294: /* ! 295: * Add the cmdBuf to the ioQueue and let the ioThread know it has ! 296: * work to do. ! 297: */ ! 298: [ioQueueLock lock]; ! 299: queue_enter(&ioQueue, ! 300: cmdBuf, ! 301: cmdBuf_t *, ! 302: link); ! 303: [ioQueueLock unlockWith:QUEUE_FULL]; ! 304: ! 305: /* ! 306: * Wait for I/O complete. ! 307: */ ! 308: [cmdBuf->cmdLock lockWhen:CMD_COMPLETE]; ! 309: [cmdBuf->cmdLock unlock]; ! 310: ! 311: return; ! 312: } ! 313: ! 314: @end ! 315: ! 316: ! 317: /* ! 318: * The I/O thread. This thread sits around waiting for work to do on ! 319: * the ioQueue, then behaves accordingly. ! 320: */ ! 321: static void MyDeviceThread(id deviceId) ! 322: { ! 323: cmdBuf_t *cmdBuf; ! 324: char in_string[40]; ! 325: ! 326: while(1) { ! 327: ! 328: /* ! 329: * Wait for something to do. ! 330: */ ! 331: cmdBuf = [deviceId waitForCmdBuf]; ! 332: ! 333: /* ! 334: * OK, What's up? ! 335: */ ! 336: switch(cmdBuf->cmd) { ! 337: case IOC_GETNUM: ! 338: /* ! 339: * Get a number from user, pass back to client. ! 340: */ ! 341: printf("MyDeviceThread: Enter number: "); ! 342: gets(in_string); ! 343: cmdBuf->aNumber = atoi(in_string); ! 344: break; ! 345: ! 346: case IOC_PRINTNUM: ! 347: /* ! 348: * Just display client's number. ! 349: */ ! 350: printf("MyDeviceThread: cmdBuf->aNumber = %d\n", ! 351: cmdBuf->aNumber); ! 352: break; ! 353: ! 354: case IOC_QUIT: ! 355: /* ! 356: * Time to die. First notify client that we got ! 357: * the command, then terminate. ! 358: */ ! 359: [deviceId cmdBufComplete:cmdBuf]; ! 360: IOExitThread(); ! 361: ! 362: } ! 363: ! 364: /* ! 365: * Notify client of I/O complete. ! 366: */ ! 367: [deviceId cmdBufComplete:cmdBuf]; ! 368: } ! 369: ! 370: /* NOT REACHED */ ! 371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.