Annotation of driverkit/Examples/UnixDisk/unixThread.m, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

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