|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.