|
|
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: /* unixThread.m 1.0 02/07/91 (c) 1991 NeXT ! 25: * ! 26: * unixThread.m - unixDisk Device Thread support. ! 27: * ! 28: * HISTORY ! 29: * 07-Feb-91 Doug Mitchell at NeXT ! 30: * Created. ! 31: */ ! 32: ! 33: #import <bsd/sys/types.h> ! 34: #import <mach/cthreads.h> ! 35: #import <driverkit/IODevice.h> ! 36: #import "unixDisk.h" ! 37: #import "unixThread.h" ! 38: #import "unixDiskUxpr.h" ! 39: #import <driverkit/generalFuncs.h> ! 40: #import <machkit/NXLock.h> ! 41: ! 42: static void unixThreadDequeue(IOQueue_t *ioQ, ! 43: BOOL needs_disk, ! 44: int threadNum); ! 45: ! 46: @implementation unixDisk(Thread) ! 47: ! 48: /* ! 49: * Enqueue an IOBuf on an IOQueue and wake up anyone (i.e., an I/O thread) ! 50: * who might be waiting for the IOBuf. ! 51: */ ! 52: - (void) enqueueIoBuf : (IOBuf_t *)buf ! 53: needs_disk : (BOOL)needs_disk ! 54: { ! 55: queue_head_t *q; ! 56: ! 57: if(needs_disk) ! 58: q = &IOQueue.q_disk; ! 59: else ! 60: q = &IOQueue.q_nodisk; ! 61: [IOQueue.qlock lock]; ! 62: queue_enter(q, buf, IOBuf_t *, ioChain); ! 63: [IOQueue.qlock unlockWith:WORK_AVAILABLE]; ! 64: xpr_ud("enqueueIoBuf: exiting. IOBuf 0x%x needs_disk %s\n", ! 65: buf, needs_disk ? (int)"TRUE" : (int)"FALSE", 3,4,5); ! 66: } ! 67: ! 68: /* ! 69: * Wakeup up I/O threads. Used for 'diskBecameReady' notification. ! 70: */ ! 71: - (void)ioThreadWakeup ! 72: { ! 73: [IOQueue.qlock lock]; ! 74: [IOQueue.qlock unlockWith:WORK_AVAILABLE]; ! 75: } ! 76: ! 77: /* ! 78: * Unlock IOQueue.qlock, updating condition variable as appropriate. ! 79: */ ! 80: - (void)unlockIOQueue ! 81: { ! 82: int queue_state; ! 83: IODiskReadyState lastReady = [self lastReadyState]; ! 84: ! 85: /* ! 86: * There's still work to do when: ! 87: * -- q_nodisk non-empty, or ! 88: * -- q_disk non-empty and we "really" have a disk. ! 89: */ ! 90: ! 91: if((!queue_empty(&IOQueue.q_nodisk)) || ! 92: ((!queue_empty(&IOQueue.q_disk)) && ! 93: (lastReady != IO_NoDisk) && ! 94: (lastReady != IO_Ejecting) && ! 95: (!IOQueue.ejectPending) ! 96: ) ! 97: ) { ! 98: queue_state = WORK_AVAILABLE; ! 99: } ! 100: else ! 101: queue_state = NO_WORK_AVAILABLE; ! 102: [IOQueue.qlock unlockWith:queue_state]; ! 103: } ! 104: ! 105: @end ! 106: ! 107: /* ! 108: * I/O thread. 'n' copies of this are IOForkThread()'d in the init:sender: ! 109: * method. This handles IOBufs which have been enqueued by exported methods ! 110: * (like read: and write:). ! 111: * ! 112: * This thread merely loops doing the following: ! 113: * -- get an IOBuf off of the IOQueue. ! 114: * -- perform the task specified in IOBuf->command. ! 115: * -- if async request, ioComplete: the result, else ! 116: * wakeup the waiting thread. ! 117: */ ! 118: ! 119: volatile void unix_thread(IOQueue_t *ioQ) ! 120: { ! 121: int threadNum; ! 122: IODiskReadyState lastReady; ! 123: ! 124: /* ! 125: * First assign ourself a thread number. ! 126: */ ! 127: [ioQ->qlock lock]; ! 128: threadNum = ioQ->numThreads++; ! 129: [ioQ->qlock unlock]; ! 130: xpr_uth("unix_thread %d: starting\n", threadNum, 2,3,4,5); ! 131: while(1) { ! 132: ! 133: /* ! 134: * Wait for something to do. Keep the lock until we ! 135: * dequeue something. ! 136: */ ! 137: [ioQ->qlock lockWhen:WORK_AVAILABLE]; ! 138: ! 139: /* ! 140: * Service all requests which do not need a disk. ! 141: */ ! 142: xpr_uth("unix_thread: servicing q_nodisk\n", 1,2,3,4,5); ! 143: while(!queue_empty(&ioQ->q_nodisk)) ! 144: unixThreadDequeue(ioQ, NO, threadNum); ! 145: ! 146: /* ! 147: * Now service all requests which need a disk, if our disk ! 148: * is present. ! 149: */ ! 150: xpr_uth("unix_thread: servicing q_disk\n", 1,2,3,4,5); ! 151: while((!queue_empty(&ioQ->q_disk)) && ! 152: ([ioQ->device lastReadyState] != IO_NoDisk) && ! 153: ([ioQ->device lastReadyState] != IO_Ejecting) && ! 154: (!ioQ->ejectPending)) { ! 155: unixThreadDequeue(ioQ, YES, threadNum); ! 156: } ! 157: ! 158: /* ! 159: * If we have work to do in q_disk but we don't have a disk, ! 160: * ask volCheck to put up a panel. In either case, when we ! 161: * unlock ioQ.qlock for the last time, update its ! 162: * condition variable as appropriate so we and the other ! 163: * I/O threads working on this IOQueue know whether or not ! 164: * to sleep. ! 165: */ ! 166: lastReady = [ioQ->device lastReadyState]; ! 167: if((!queue_empty(&ioQ->q_disk)) && ! 168: ((lastReady == IO_NoDisk) || ioQ->ejectPending)) { ! 169: [ioQ->device unlockIOQueue]; ! 170: xpr_uth("unix_thread: volCheckRequest()\n", 1,2,3,4,5); ! 171: volCheckRequest(ioQ->device, ! 172: [ioQ->device diskType]); ! 173: } ! 174: else { ! 175: [ioQ->device unlockIOQueue]; ! 176: } ! 177: } ! 178: /* NOT REACHED */ ! 179: } ! 180: ! 181: /* ! 182: * Process a request at the head of one of the queues in *ioQ. ! 183: * ioQ->qlock must be held on entry; it will still be held on exit (though we ! 184: * release it when doing a command dispatch). ! 185: */ ! 186: static void unixThreadDequeue(IOQueue_t *ioQ, ! 187: BOOL needs_disk, ! 188: int threadNum) ! 189: { ! 190: queue_head_t *q; ! 191: IOBuf_t *IOBuf; ! 192: ! 193: if(needs_disk) ! 194: q = &ioQ->q_disk; ! 195: else ! 196: q = &ioQ->q_nodisk; ! 197: if(queue_empty(q)) { ! 198: IOLog("unixThreadDequeue: Empty queue!\n"); ! 199: return; ! 200: } ! 201: IOBuf = (IOBuf_t *)queue_first(q); ! 202: queue_remove(q, ! 203: IOBuf, ! 204: IOBuf_t *, ! 205: ioChain); ! 206: ! 207: /* ! 208: * For proper timing of the call to volCheckEjecting, we have to ! 209: * determine right now - while the queue is locked - whether this ! 210: * is an eject command. If so, the call to volCheckEjecting() will ! 211: * prevent other I/O threads from attempting to perform I/Os from ! 212: * q_disk. ! 213: * ! 214: * The numDiskIos counter allows the thread doing an eject command ! 215: * to wait for all other pending Disk I/Os to complete before doing ! 216: * the eject. ! 217: * ! 218: * We also have to keep that cruft ejectPending flag around, since ! 219: * the call to volCheckEjecting() doesn't result in an immediate ! 220: * update of lastReadyState... ! 221: */ ! 222: if(needs_disk) { ! 223: [ioQ->ejectLock lock]; ! 224: ioQ->numDiskIos++; ! 225: if(IOBuf->command == @selector(deviceEject:threadNum:)) { ! 226: ioQ->ejectPending = TRUE; ! 227: volCheckEjecting(IOBuf->device, ! 228: [IOBuf->device diskType]); ! 229: } ! 230: [ioQ->ejectLock unlockWith:ioQ->numDiskIos]; ! 231: } ! 232: ! 233: [ioQ->qlock unlock]; ! 234: xpr_uth("unix_thread %d: IOBuf 0x%x received\n", ! 235: threadNum, IOBuf, 3,4,5); ! 236: [IOBuf->device perform:IOBuf->command ! 237: with:(id)IOBuf ! 238: with:(id)threadNum]; ! 239: [ioQ->qlock lock]; ! 240: if(needs_disk) { ! 241: /* ! 242: * Enable possible waiting eject command. ! 243: */ ! 244: [ioQ->ejectLock lock]; ! 245: ioQ->numDiskIos--; ! 246: [ioQ->ejectLock unlockWith:ioQ->numDiskIos]; ! 247: } ! 248: } ! 249: ! 250: /* end of IOThread.m */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.