Annotation of driverkit/Examples/UnixDisk/unixThread.m, revision 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.