Annotation of kernel/bsd/netat/adsp_Close.c, 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: 
        !            25: /*
        !            26:  *     Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
        !            27:  *     All Rights Reserved.
        !            28:  *
        !            29:  *     THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF APPLE COMPUTER, INC.
        !            30:  *     The copyright notice above does not evidence any actual or
        !            31:  *     intended publication of such source code.
        !            32:  */
        !            33: 
        !            34: 
        !            35: #include       <adsp_local.h>
        !            36: extern atlock_t adspall_lock;
        !            37: 
        !            38: static void qRemove(CCBPtr, CCBPtr);
        !            39: 
        !            40: 
        !            41: /*
        !            42:  * CheckOkToClose
        !            43:  * 
        !            44:  * Check to see if it is OK to close this connection cleanly.
        !            45:  *
        !            46:  * INPUTS:
        !            47:  *             Stream pointer
        !            48:  * OUTPUTS:
        !            49:  *             True if no outstanding transactions and we can close cleanly
        !            50:  */
        !            51: int CheckOkToClose(sp)         /* (CCBPtr sp) */
        !            52:     CCBPtr sp;
        !            53: {
        !            54:     
        !            55:     if (sp->sData)             /* Outstanding data ? */
        !            56:        return 0;
        !            57: 
        !            58:     if (sp->sapb)              /* Outstanding send attention ? */
        !            59:        return 0;
        !            60: 
        !            61:     if (sp->frpb)              /* Outstanding forward reset ? */
        !            62:        return 0;
        !            63:                
        !            64:     if (sp->sendAttnAck)
        !            65:        return 0;
        !            66:                
        !            67:     if (sp->sendDataAck)
        !            68:        return 0;
        !            69:        
        !            70:     /*
        !            71:      * Must be OK to close
        !            72:      */
        !            73:     sp->sendCtl        |= B_CTL_CLOSE; /* So, need to send close advice */
        !            74:     sp->callSend = 1;
        !            75: 
        !            76:     return 1;                  /* It's OK to close */
        !            77: }
        !            78: 
        !            79: 
        !            80: /*
        !            81:  * CompleteQueue
        !            82:  * 
        !            83:  * Given the address of the head of a queue of DSP parameter blocks, zero 
        !            84:  * the queue, and complete each item on the queue with the given result 
        !            85:  * code.
        !            86:  *
        !            87:  * INPUTS:
        !            88:  *             qhead           Address of ptr to first queue element
        !            89:  *             code            The result code
        !            90:  * OUTPUTS:
        !            91:  *             none
        !            92:  */
        !            93: int  CompleteQueue(qhead, code)        /* (DSPPBPtr FPTR qhead, OSErr code) */
        !            94:     struct adspcmd **qhead;
        !            95:     int code;
        !            96: {
        !            97:     register struct adspcmd *p;
        !            98:     register struct adspcmd *n;
        !            99:     register gref_t *gref;
        !           100:     register int    total = 0;
        !           101:     CCBPtr sp = 0;
        !           102:     int s;
        !           103: 
        !           104:     n = *qhead;                        /* Get first item */
        !           105:     *qhead = 0;                        /* Zero out the queue */
        !           106:     if (n) {
        !           107:        gref = n->gref;
        !           108:        if (gref->info) {
        !           109:            sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
        !           110:            atalk_flush(sp->gref);
        !           111:            ATDISABLE(s, sp->lock);
        !           112:            }
        !           113:     }
        !           114: 
        !           115:     while (p = n) {            /* while items left */
        !           116:        n = (struct adspcmd *)(p->qLink); /* Save next guy */
        !           117:        p->ioResult = code;
        !           118:        if (sp) {
        !           119:            completepb(sp, p);  /* complete the copy of the request */
        !           120:            total++;
        !           121:        } else
        !           122:            gbuf_freem(p->mp);
        !           123:     }                          /* while */
        !           124:     if (sp)
        !           125:        ATENABLE(s, sp->lock);
        !           126:     return(total);
        !           127: }
        !           128: 
        !           129: /*
        !           130:  * RemoveCCB
        !           131:  * 
        !           132:  * Called from do close to free up the user's CCB.  So, we remove the 
        !           133:  * CCB from the list of CCB's.
        !           134:  *
        !           135:  * INPUTS:
        !           136:  *             sp      pointer to ccb
        !           137:  *             pb      a remove param block to complete when done
        !           138:  * OUTPUTS:
        !           139:  *             none
        !           140:  */
        !           141: 
        !           142: void RemoveCCB(sp, pb)         /* (CCBPtr sp, DSPPBPtr pb) */
        !           143:     CCBPtr sp;
        !           144:     struct adspcmd *pb;
        !           145: {
        !           146:        gref_t *gref;
        !           147:        
        !           148:        if (sp->gref == 0)
        !           149:                return;
        !           150:     /*
        !           151:      * Unlink CCB from list
        !           152:      */
        !           153:     qRemove(AT_ADSP_STREAMS, sp); /* remove sp from active streams queue */
        !           154: 
        !           155:     if (pb) {
        !           156:        pb->ioResult = 0;
        !           157:        if (pb->ioc)            /* is this a current or queued request */
        !           158:            adspioc_ack(0, pb->ioc, pb->gref);  /* current */
        !           159:        else {
        !           160:            completepb(sp, pb); /* queued */
        !           161:        }
        !           162:        
        !           163:        if (sp->opb && (pb != sp->opb)) { /* if the pb requested is not the */
        !           164:            pb = sp->opb;               /* waiting open pb, complete it too */
        !           165:            sp->opb = 0;
        !           166:            pb->ioResult = 0;
        !           167:            completepb(sp, pb);
        !           168:        } else {
        !           169:            sp->opb = 0;
        !           170:         }
        !           171:     }
        !           172:     gref = sp->gref;
        !           173:     sp->gref = 0;
        !           174:     if (gref->info == (char *)sp->sp_mp) { /* queue head is still valid */
        !           175:            unsigned char skt;
        !           176: 
        !           177:            if ((skt = sp->localSocket) != 0) {
        !           178:              if (adspDeassignSocket(sp) == 0)
        !           179:                  ddp_notify_nbp(skt, sp->pid, DDP_ADSP);
        !           180:            }
        !           181: 
        !           182:          if (gref->info) {
        !           183:            gbuf_freem((gbuf_t *)gref->info);   /* free the CCB */
        !           184:            gref->info = 0;
        !           185:          }
        !           186:     } else
        !           187:        gbuf_freem(sp->sp_mp);  /* our head is already gone, be sure
        !           188:                                 * to release our resources too */
        !           189: }
        !           190: 
        !           191: int  AbortIO(sp, err)
        !           192:     CCBPtr sp;
        !           193:     OSErr err;
        !           194: {
        !           195:     register int    total;
        !           196: 
        !           197:        if (sp->gref == 0)
        !           198:                return 0;
        !           199:     /*
        !           200:      * Complete all outstanding transactions.  
        !           201:      */
        !           202:     total += CompleteQueue(&sp->sapb, err); /* Abort outstanding send attentions */
        !           203:     CompleteQueue(&sp->frpb, err); /* Abort outstanding forward resets */
        !           204: 
        !           205:     if (sp->sbuf_mb) { /* clear the send queue */
        !           206:        gbuf_freel(sp->sbuf_mb);
        !           207:        sp->sbuf_mb = 0;
        !           208:     }
        !           209: 
        !           210:     if (sp->csbuf_mb) {
        !           211:        gbuf_freem(sp->csbuf_mb);
        !           212:        sp->csbuf_mb = 0;
        !           213:     }
        !           214:     sp->sData = 0;
        !           215:     
        !           216:     return(total);
        !           217: }
        !           218: 
        !           219: /*
        !           220:  * DoClose
        !           221:  * 
        !           222:  * Called from several places (probe timeout, recv close advice, 
        !           223:  * dspRemove, etc.) to change state of connection to closed and 
        !           224:  * complete all outstanding I/O.
        !           225:  *
        !           226:  * Will also remove the CCB if there is a dsp remove pending.
        !           227:  *
        !           228:  * INPUTS:
        !           229:  *             sp              An ADSP stream
        !           230:  * OUTPUTS:
        !           231:  *             none
        !           232:  */
        !           233: void DoClose(sp, err, force_abort)     /* (CCBPtr sp, OSErr err) */
        !           234:     register CCBPtr sp;
        !           235:     int err;
        !           236: {
        !           237:     register struct adspcmd *pb, *np;
        !           238:     register gbuf_t *mp;
        !           239:     int      aborted_count;
        !           240:        
        !           241:     dPrintf(D_M_ADSP, D_L_TRACE, ("DoClose: pid=%d,e=%d,a=%d,s=%d,r=%d\n",
        !           242:                sp->pid, err, force_abort, sp->localSocket, sp->removing));
        !           243:     sp->userFlags |= eClosed; /* Set flag */
        !           244:     sp->state = sClosed;
        !           245:     sp->openState = O_STATE_NOTHING;
        !           246: 
        !           247:     /*
        !           248:      * Clean up any timer elements
        !           249:      */
        !           250:     RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
        !           251:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer);
        !           252:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
        !           253:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer);
        !           254:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->ResetTimer);
        !           255: 
        !           256:     aborted_count = AbortIO(sp, err);
        !           257:     np = sp->opb;              /* Get list of close/removes to complete */
        !           258:     sp->opb = 0;               /* set this list null */
        !           259:        
        !           260:     while (pb = np) {          /* Handle all of the close/remove param blks */
        !           261:        np = (struct adspcmd *)pb->qLink; /* Get next guy (if any) */
        !           262:        pb->qLink = 0;
        !           263:        pb->ioResult = err;
        !           264:        completepb(sp, pb);
        !           265:     }
        !           266:     if (sp->removing && (force_abort >= 0)) {        /* Abort outstanding receives */
        !           267:        aborted_count += CompleteQueue(&sp->rpb, err);
        !           268: 
        !           269:        if (sp->deferred_mb) {
        !           270:                gbuf_freel(sp->deferred_mb);
        !           271:                sp->deferred_mb = 0;
        !           272:        }
        !           273:        if (sp->attn_mb) {
        !           274:                gbuf_freem(sp->attn_mb);
        !           275:                sp->attn_mb = 0;
        !           276:        }
        !           277:        if (sp->rbuf_mb) { /* clear the rcv queue */
        !           278:                gbuf_freem(sp->rbuf_mb);
        !           279:                sp->rbuf_mb = 0;
        !           280:        }
        !           281:        if (sp->crbuf_mb) {
        !           282:                gbuf_freem(sp->crbuf_mb);
        !           283:                sp->crbuf_mb = 0;
        !           284:        }
        !           285:        sp->rData = 0;
        !           286: 
        !           287:        /* if our connection has been timed out */
        !           288:        /* and the user wasn't notified of the TearDown */
        !           289:        /* because of pending requests on this socket */
        !           290:        /* then fake a read completion to force the notification */
        !           291: 
        !           292:        if (force_abort && aborted_count == 0) {
        !           293:            if (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) {
        !           294:                pb = (struct adspcmd *)gbuf_rptr(mp);
        !           295:                gbuf_wset(mp,sizeof(struct adspcmd));
        !           296: 
        !           297:                bzero((caddr_t) pb, sizeof(struct adspcmd));
        !           298:                pb->mp = mp;
        !           299:                pb->csCode = dspRead;
        !           300:                pb->ioResult = errAborted;
        !           301:                completepb(sp, pb);             /* send fake read completion */
        !           302:            }
        !           303:        }
        !           304:        sp->removing = 0;
        !           305:        RemoveCCB(sp, 0); /* Will call completion routine */
        !           306:     }
        !           307:     sp->userFlags &= ~eClosed;
        !           308: }
        !           309: 
        !           310: 
        !           311: /*
        !           312:  * dspClose
        !           313:  * 
        !           314:  * Also called for dspRemove and dspCLRemove.
        !           315:  * Must handle case of multiple close calls being issued (without 
        !           316:  * abort bit set) Can only allow one pending remove though.
        !           317:  *
        !           318:  * INPUTS:
        !           319:  *     -->     ccbRefNum               refnum of connection end
        !           320:  *     -->     abort                   abort the connection
        !           321:  *
        !           322:  * OUTPUTS:
        !           323:  *     none
        !           324:  *
        !           325:  * ERRORS:
        !           326:  *             errRefNum               Bad connection Refnum
        !           327:  */
        !           328: int adspClose(sp, pb)          /* (DSPPBPtr pb) */
        !           329:     register CCBPtr sp;
        !           330:     register struct adspcmd *pb;
        !           331: {
        !           332:     int        s;
        !           333:     register gbuf_t *mp;
        !           334:        
        !           335:     /* Must execute nearly all of this with ints off because user could 
        !           336:      * be issuing a second dspRemove while the first is pending.  Until 
        !           337:      * we can detect this, we must not allow interrupts.
        !           338:      * Also, we can't handle the case where a close was issued earlier, 
        !           339:      * and now this is the remove.  If the write completion for the 
        !           340:      * close advice packet occurs in the middle of this, we might screw up. 
        !           341:      */
        !           342: 
        !           343:     if (sp == 0) {
        !           344:        pb->ioResult = errRefNum;
        !           345:        return EINVAL;
        !           346:     }
        !           347: 
        !           348:     /*
        !           349:      * Handle dspCLRemove
        !           350:      */
        !           351:     if (pb->csCode == (short)dspCLRemove) { /* Remove connection listener */
        !           352:        if (sp->state != (short)sListening) { /* But it's not a listener! */
        !           353:            pb->ioResult = errState;
        !           354:            return EINVAL;
        !           355:        }
        !           356:        CompleteQueue(&sp->opb, errAborted); /* Complete all dspListens */
        !           357:        RemoveCCB(sp, pb);      /* Will call completion routine */
        !           358:        return 0;
        !           359:     }
        !           360: 
        !           361: 
        !           362:     /*
        !           363:      * Either dspClose or dspRemove
        !           364:      */
        !           365: 
        !           366:     if (sp->removing) {                /* Don't allow dspRemove or dspClose */
        !           367:                                /* after one dspRemove has been issued. */
        !           368:        pb->ioResult = errState;
        !           369:        return EINVAL;
        !           370:     }
        !           371: 
        !           372: 
        !           373:     /*
        !           374:      * The previous Macintosh ADSP allowed you to call close on a 
        !           375:      * connection that was in the process of opening or passively 
        !           376:      * waiting for an open request. It is also legal to close a 
        !           377:      * connection that is already closed.  No error will be generated.
        !           378:      *
        !           379:      * It is also legal to issue a second close call while the first 
        !           380:      * is still pending.
        !           381:      */
        !           382:     if (pb->csCode == (short)dspClose) {
        !           383:        ATDISABLE(s, sp->lock);
        !           384:        if ((sp->state == (short)sPassive) || (sp->state == (short)sOpening)) {
        !           385:            sp->state = sClosed;
        !           386:            ATENABLE(s, sp->lock);
        !           387:            DoClose(sp, errAborted, 0);
        !           388:            pb->ioResult = 0;
        !           389:            adspioc_ack(0, pb->ioc, pb->gref);
        !           390:            return 0;
        !           391:        }
        !           392:                
        !           393:        if (sp->state == (word)sClosed) { /* Ok to close a closed connection */
        !           394:            ATENABLE(s, sp->lock);
        !           395:            pb->ioResult = 0;
        !           396:            adspioc_ack(0, pb->ioc, pb->gref);
        !           397:            return 0;
        !           398:        }
        !           399:        if ((sp->state != (word)sOpen) && (sp->state != (word)sClosing)) {
        !           400:            ATENABLE(s, sp->lock);
        !           401:            pb->ioResult = errState;
        !           402:            return EINVAL;
        !           403:        }
        !           404:                
        !           405:        sp->state = sClosing;   /* No matter what, we're closing */
        !           406:        ATENABLE(s, sp->lock);
        !           407:     }                          /* dspClose */
        !           408:     
        !           409:     else {                     /* dspRemove */
        !           410:        ATDISABLE(s, sp->lock);
        !           411:        sp->removing = 1;       /* Prevent allowing another dspClose. */
        !           412:                                /* Tells completion routine of close */
        !           413:                                /* packet to remove us. */
        !           414: 
        !           415:        if (sp->state == sPassive || sp->state == sClosed || 
        !           416:            sp->state == sOpening) {
        !           417:            sp->state = sClosed;
        !           418:            ATENABLE(s, sp->lock);
        !           419:            DoClose(sp, errAborted, 0); /* Will remove CCB! */
        !           420:            return 0;
        !           421:        } else {                        /* sClosing & sOpen */
        !           422:            sp->state = sClosing;
        !           423:            ATENABLE(s, sp->lock);
        !           424:        }
        !           425:        
        !           426:     }                          /* dspRemove */
        !           427: 
        !           428:     if (pb->u.closeParams.abort || CheckOkToClose(sp)) /* going to close */
        !           429:     {
        !           430:        AbortIO(sp, errAborted);
        !           431:        sp->sendCtl = B_CTL_CLOSE; /* Send close advice */
        !           432:     }
        !           433: 
        !           434:     pb->ioResult = 1;
        !           435:     if ( (mp = gbuf_copym(pb->mp)) ) { /* duplicate user request */
        !           436:            adspioc_ack(0, pb->ioc, pb->gref); /* release user */
        !           437:            pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */
        !           438:            pb->ioc = 0;
        !           439:            pb->mp = mp;
        !           440:            ATDISABLE(s, sp->lock);
        !           441:            qAddToEnd(&sp->opb, pb);    /* and save it */
        !           442:            ATENABLE(s, sp->lock);
        !           443:     } else {
        !           444:            pb->ioResult = 0;
        !           445:            adspioc_ack(0, pb->ioc, pb->gref); /* release user, and keep no copy
        !           446:                                             * for kernel bookkeeping, yetch!
        !           447:                                             */
        !           448:     }
        !           449:     CheckSend(sp);
        !           450: 
        !           451:     return 0;
        !           452: }
        !           453: 
        !           454: static void qRemove(qptr, elem)
        !           455:     register CCBPtr qptr;
        !           456:     register CCBPtr elem;
        !           457: {
        !           458:        int s;
        !           459: 
        !           460:        ATDISABLE(s, adspall_lock);
        !           461:     while(qptr->ccbLink) {
        !           462:        if ((DSPPBPtr)(qptr->ccbLink) == (DSPPBPtr)elem) {
        !           463:            qptr->ccbLink = elem->ccbLink;
        !           464:            elem->ccbLink = 0;
        !           465:            ATENABLE(s, adspall_lock);
        !           466:            return;
        !           467:        }
        !           468:        qptr = qptr->ccbLink;
        !           469:     }
        !           470:        ATENABLE(s, adspall_lock);
        !           471: }
        !           472: 
        !           473: int RxClose(sp)
        !           474:     register CCBPtr sp;
        !           475: {
        !           476:     register gbuf_t *mp;
        !           477:     register struct adspcmd *pb;
        !           478:        int s, l;
        !           479: 
        !           480:        ATDISABLE(l, sp->lockClose);
        !           481:        ATDISABLE(s, sp->lock);
        !           482:        if ((sp->state == sClosing) || (sp->state == sClosed)) {
        !           483:                ATENABLE(s, sp->lock);
        !           484:                ATENABLE(l, sp->lockClose);
        !           485:                return 0;
        !           486:        }
        !           487:     sp->state = sClosed;
        !           488:        ATENABLE(s, sp->lock);
        !           489:     CheckReadQueue(sp);                /* try to deliver all remaining data */
        !           490: 
        !           491:     if ( (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) ) {
        !           492:         pb = (struct adspcmd *)gbuf_rptr(mp);
        !           493:        gbuf_wset(mp,sizeof(struct adspcmd));
        !           494:        pb->ioc = 0;
        !           495:        pb->mp = mp;
        !           496: 
        !           497:        pb->csCode = dspClose;
        !           498:        pb->ioResult = 0;
        !           499:        completepb(sp, pb);             /* send close completion */
        !           500:     }
        !           501: 
        !           502: if ((sp->userFlags & eClosed) == 0)
        !           503:     DoClose(sp, errAborted, -1);       /* abort send requests and timers */
        !           504: 
        !           505:        ATENABLE(l, sp->lockClose);
        !           506:     return 0;
        !           507: }

unix.superglobalmegacorp.com

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