Annotation of ntddk/src/comm/serial/waitmask.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
                      4: 
                      5: Module Name:
                      6: 
                      7:     waitmask.c
                      8: 
                      9: Abstract:
                     10: 
                     11:     This module contains the code that is very specific to get/set/wait
                     12:     on event mask operations in the serial driver
                     13: 
                     14: Author:
                     15: 
                     16:     Anthony V. Ercolano 26-Sep-1991
                     17: 
                     18: Environment:
                     19: 
                     20:     Kernel mode
                     21: 
                     22: Revision History :
                     23: 
                     24: --*/
                     25: 
                     26: #include <stddef.h>
                     27: #include "ntddk.h"
                     28: #include "ntddser.h"
                     29: #include "serial.h"
                     30: #include "serialp.h"
                     31: 
                     32: 
                     33: BOOLEAN
                     34: SerialGrabWaitFromIsr(
                     35:     IN PVOID Context
                     36:     );
                     37: 
                     38: BOOLEAN
                     39: SerialGiveWaitToIsr(
                     40:     IN PVOID Context
                     41:     );
                     42: 
                     43: BOOLEAN
                     44: SerialFinishOldWait(
                     45:     IN PVOID Context
                     46:     );
                     47: 
                     48: 
                     49: NTSTATUS
                     50: SerialStartMask(
                     51:     IN PSERIAL_DEVICE_EXTENSION Extension
                     52:     )
                     53: 
                     54: /*++
                     55: 
                     56: Routine Description:
                     57: 
                     58:     This routine is used to process the set mask and wait
                     59:     mask ioctls.  Calls to this routine are serialized by
                     60:     placing irps in the list under the protection of the
                     61:     cancel spin lock.
                     62: 
                     63: Arguments:
                     64: 
                     65:     Extension - A pointer to the serial device extension.
                     66: 
                     67: Return Value:
                     68: 
                     69:     Will return pending for everything put the first
                     70:     request that we actually process.  Even in that
                     71:     case it will return pending unless it can complete
                     72:     it right away.
                     73: 
                     74: 
                     75: --*/
                     76: 
                     77: {
                     78: 
                     79:     //
                     80:     // The current stack location.  This contains much of the
                     81:     // information we need to process this particular request.
                     82:     //
                     83:     PIO_STACK_LOCATION IrpSp;
                     84: 
                     85:     PIRP NewIrp;
                     86: 
                     87:     BOOLEAN SetFirstStatus = FALSE;
                     88:     NTSTATUS FirstStatus;
                     89: 
                     90:     SerialDump(
                     91:         SERDIAG3,
                     92:         ("SERIAL: In SerialStartMask\n")
                     93:         );
                     94: 
                     95:     ASSERT(Extension->CurrentMaskIrp);
                     96: 
                     97:     do {
                     98: 
                     99:         SerialDump(
                    100:             SERDIAG4,
                    101:             ("SERIAL: STARMASK - CurrentMaskIrp: %x\n",Extension->CurrentMaskIrp)
                    102:             );
                    103:         IrpSp = IoGetCurrentIrpStackLocation(Extension->CurrentMaskIrp);
                    104: 
                    105:         ASSERT((IrpSp->Parameters.DeviceIoControl.IoControlCode ==
                    106:                 IOCTL_SERIAL_WAIT_ON_MASK) ||
                    107:                (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
                    108:                 IOCTL_SERIAL_SET_WAIT_MASK));
                    109: 
                    110:         if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
                    111:             IOCTL_SERIAL_SET_WAIT_MASK) {
                    112: 
                    113:             SerialDump(
                    114:                 SERDIAG4,
                    115:                 ("SERIAL - %x is a SETMASK irp\n",Extension->CurrentMaskIrp)
                    116:                 );
                    117: 
                    118:             //
                    119:             // Complete the old wait if there is one.
                    120:             //
                    121: 
                    122:             KeSynchronizeExecution(
                    123:                 Extension->Interrupt,
                    124:                 SerialFinishOldWait,
                    125:                 Extension
                    126:                 );
                    127: 
                    128:             //
                    129:             // Any current waits should be on its way to completion
                    130:             // at this point.  There certainly shouldn't be any
                    131:             // irp mask location.
                    132:             //
                    133: 
                    134:             ASSERT(!Extension->IrpMaskLocation);
                    135: 
                    136:             Extension->CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
                    137: 
                    138:             if (!SetFirstStatus) {
                    139: 
                    140:                 SerialDump(
                    141:                     SERDIAG4,
                    142:                     ("SERIAL: %x was the first irp processed by this\n"
                    143:                      "------- invocation of startmask\n",Extension->CurrentMaskIrp)
                    144:                     );
                    145:                 FirstStatus = STATUS_SUCCESS;
                    146:                 SetFirstStatus = TRUE;
                    147: 
                    148:             }
                    149: 
                    150:             //
                    151:             // The following call will also cause the current
                    152:             // call to be completed.
                    153:             //
                    154: 
                    155:             SerialGetNextIrp(
                    156:                 &Extension->CurrentMaskIrp,
                    157:                 &Extension->MaskQueue,
                    158:                 &NewIrp,
                    159:                 TRUE
                    160:                 );
                    161:             SerialDump(
                    162:                 SERDIAG4,
                    163:                 ("SERIAL: Perhaps another mask irp was found in the queue\n"
                    164:                  "------- %x/%x <- values should be the same\n",
                    165:                  Extension->CurrentMaskIrp,NewIrp)
                    166:                 );
                    167: 
                    168: 
                    169:         } else {
                    170: 
                    171:             //
                    172:             // First make sure that we have a non-zero mask.
                    173:             // If the app queues a wait on a zero mask it can't
                    174:             // be statisfied so it makes no sense to start it.
                    175:             //
                    176: 
                    177:             if ((!Extension->IsrWaitMask) || (Extension->CurrentWaitIrp)) {
                    178: 
                    179:                 SerialDump(
                    180:                     SERDIAG4,
                    181:                     ("SERIAL: WaitIrp is invalid\n"
                    182:                      "------- IsrWaitMask: %x\n"
                    183:                      "------- CurrentWaitIrp: %x\n",
                    184:                      Extension->IsrWaitMask,
                    185:                      Extension->CurrentWaitIrp)
                    186:                     );
                    187: 
                    188:                 Extension->CurrentMaskIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                    189: 
                    190:                 if (!SetFirstStatus) {
                    191: 
                    192:                     SerialDump(
                    193:                         SERDIAG4,
                    194:                         ("SERIAL: %x was the first irp processed by this\n"
                    195:                          "------- invocation of startmask\n",Extension->CurrentMaskIrp)
                    196:                         );
                    197:                     FirstStatus = STATUS_INVALID_PARAMETER;
                    198:                     SetFirstStatus = TRUE;
                    199: 
                    200:                 }
                    201: 
                    202:                 SerialGetNextIrp(
                    203:                     &Extension->CurrentMaskIrp,
                    204:                     &Extension->MaskQueue,
                    205:                     &NewIrp,
                    206:                     TRUE
                    207:                     );
                    208:                 SerialDump(
                    209:                     SERDIAG4,
                    210:                     ("SERIAL: Perhaps another mask irp was found in the queue\n"
                    211:                      "------- %x/%x <- values should be the same\n",
                    212:                      Extension->CurrentMaskIrp,NewIrp)
                    213:                     );
                    214: 
                    215:             } else {
                    216: 
                    217:                 KIRQL OldIrql;
                    218: 
                    219:                 //
                    220:                 // Make the current mask irp the current wait irp and
                    221:                 // get a new current mask irp.  Note that when we get
                    222:                 // the new current mask irp we DO NOT complete the
                    223:                 // old current mask irp (which is now the current wait
                    224:                 // irp.
                    225:                 //
                    226:                 // Then under the protection of the cancel spin lock
                    227:                 // we check to see if the current wait irp needs to
                    228:                 // be canceled
                    229:                 //
                    230: 
                    231:                 IoAcquireCancelSpinLock(&OldIrql);
                    232: 
                    233:                 if (Extension->CurrentMaskIrp->Cancel) {
                    234: 
                    235:                     SerialDump(
                    236:                         SERDIAG4,
                    237:                         ("SERIAL: %x irp was already marked as cancelled\n",
                    238:                          Extension->CurrentMaskIrp)
                    239:                         );
                    240:                     IoReleaseCancelSpinLock(OldIrql);
                    241:                     Extension->CurrentMaskIrp->IoStatus.Status = STATUS_CANCELLED;
                    242: 
                    243:                     if (!SetFirstStatus) {
                    244: 
                    245:                         SerialDump(
                    246:                             SERDIAG4,
                    247:                             ("SERIAL: %x was the first irp processed by this\n"
                    248:                              "------- invocation of startmask\n",Extension->CurrentMaskIrp)
                    249:                             );
                    250:                         FirstStatus = STATUS_CANCELLED;
                    251:                         SetFirstStatus = TRUE;
                    252: 
                    253:                     }
                    254: 
                    255:                     SerialGetNextIrp(
                    256:                         &Extension->CurrentMaskIrp,
                    257:                         &Extension->MaskQueue,
                    258:                         &NewIrp,
                    259:                         TRUE
                    260:                         );
                    261:                     SerialDump(
                    262:                         SERDIAG4,
                    263:                         ("SERIAL: Perhaps another mask irp was found in the queue\n"
                    264:                          "------- %x/%x <- values should be the same\n",
                    265:                          Extension->CurrentMaskIrp,NewIrp)
                    266:                         );
                    267: 
                    268:                 } else {
                    269: 
                    270:                     SerialDump(
                    271:                         SERDIAG4,
                    272:                         ("SERIAL: %x will become the current wait irp\n",
                    273:                          Extension->CurrentMaskIrp)
                    274:                         );
                    275:                     if (!SetFirstStatus) {
                    276: 
                    277:                         SerialDump(
                    278:                             SERDIAG4,
                    279:                             ("SERIAL: %x was the first irp processed by this\n"
                    280:                              "------- invocation of startmask\n",Extension->CurrentMaskIrp)
                    281:                             );
                    282:                         FirstStatus = STATUS_PENDING;
                    283:                         SetFirstStatus = TRUE;
                    284: 
                    285:                         //
                    286:                         // If we haven't already set a first status
                    287:                         // then there is a chance that this packet
                    288:                         // was never on the queue.  We should mark
                    289:                         // it as pending.
                    290:                         //
                    291: 
                    292:                         IoMarkIrpPending(Extension->CurrentMaskIrp);
                    293: 
                    294:                     }
                    295: 
                    296:                     //
                    297:                     // There should never be a mask location when
                    298:                     // there isn't a current wait irp.  At this point
                    299:                     // there shouldn't be a current wait irp also.
                    300:                     //
                    301: 
                    302:                     ASSERT(!Extension->IrpMaskLocation);
                    303:                     ASSERT(!Extension->CurrentWaitIrp);
                    304: 
                    305:                     Extension->CurrentWaitIrp = Extension->CurrentMaskIrp;
                    306:                     SERIAL_INIT_REFERENCE(Extension->CurrentWaitIrp);
                    307:                     IoSetCancelRoutine(
                    308:                         Extension->CurrentWaitIrp,
                    309:                         SerialCancelWait
                    310:                         );
                    311: 
                    312:                     //
                    313:                     // Since the cancel routine has a reference to
                    314:                     // the irp we need to update the reference
                    315:                     // count.
                    316:                     //
                    317: 
                    318:                     SERIAL_INC_REFERENCE(Extension->CurrentWaitIrp);
                    319: 
                    320:                     KeSynchronizeExecution(
                    321:                         Extension->Interrupt,
                    322:                         SerialGiveWaitToIsr,
                    323:                         Extension
                    324:                         );
                    325: 
                    326:                     IoReleaseCancelSpinLock(OldIrql);
                    327: 
                    328:                     SerialGetNextIrp(
                    329:                         &Extension->CurrentMaskIrp,
                    330:                         &Extension->MaskQueue,
                    331:                         &NewIrp,
                    332:                         FALSE
                    333:                         );
                    334:                     SerialDump(
                    335:                         SERDIAG4,
                    336:                         ("SERIAL: Perhaps another mask irp was found in the queue\n"
                    337:                          "------- %x/%x <- values should be the same\n",
                    338:                          Extension->CurrentMaskIrp,NewIrp)
                    339:                         );
                    340: 
                    341:                 }
                    342: 
                    343:             }
                    344: 
                    345:         }
                    346: 
                    347:     } while (NewIrp);
                    348: 
                    349:     return FirstStatus;
                    350: 
                    351: }
                    352: 
                    353: BOOLEAN
                    354: SerialGrabWaitFromIsr(
                    355:     IN PVOID Context
                    356:     )
                    357: 
                    358: /*++
                    359: 
                    360: Routine Description:
                    361: 
                    362:     This routine will check to see if the ISR still knows about
                    363:     a wait irp by checking to see if the IrpMaskLocation is non-null.
                    364:     If it is then it will zero the Irpmasklocation (which in effect
                    365:     grabs the irp away from the isr).  This routine is only called
                    366:     buy the cancel code for the wait.
                    367: 
                    368:     NOTE: This is called by KeSynchronizeExecution.
                    369: 
                    370: Arguments:
                    371: 
                    372:     Context - A pointer to the device extension
                    373: 
                    374: Return Value:
                    375: 
                    376:     Always FALSE.
                    377: 
                    378: --*/
                    379: 
                    380: {
                    381: 
                    382:     PSERIAL_DEVICE_EXTENSION Extension = Context;
                    383: 
                    384:     SerialDump(
                    385:         SERDIAG3,
                    386:         ("SERIAL: In SerialGrabWaitFromIsr\n")
                    387:         );
                    388: 
                    389:     if (Extension->IrpMaskLocation) {
                    390: 
                    391:         SerialDump(
                    392:             SERDIAG4,
                    393:             ("SERIAL: The isr still owns the irp %x, mask location is %x\n"
                    394:              "------- and system buffer is %x\n",
                    395:              Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
                    396:              Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer)
                    397:             );
                    398: 
                    399:         //
                    400:         // The isr still "owns" the irp.
                    401:         //
                    402: 
                    403:         *Extension->IrpMaskLocation = 0;
                    404:         Extension->IrpMaskLocation = NULL;
                    405: 
                    406:         Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
                    407: 
                    408:         //
                    409:         // Since the isr no longer references the irp we need to
                    410:         // decrement the reference count.
                    411:         //
                    412: 
                    413:         SERIAL_DEC_REFERENCE(Extension->CurrentWaitIrp);
                    414: 
                    415:     }
                    416: 
                    417:     return FALSE;
                    418: }
                    419: 
                    420: BOOLEAN
                    421: SerialGiveWaitToIsr(
                    422:     IN PVOID Context
                    423:     )
                    424: 
                    425: /*++
                    426: 
                    427: Routine Description:
                    428: 
                    429:     This routine simply sets a variable in the device extension
                    430:     so that the isr knows that we have a wait irp.
                    431: 
                    432:     NOTE: This is called by KeSynchronizeExecution.
                    433: 
                    434:     NOTE: This routine assumes that it is called with the
                    435:           cancel spinlock held.
                    436: 
                    437: Arguments:
                    438: 
                    439:     Context - Simply a pointer to the device extension.
                    440: 
                    441: Return Value:
                    442: 
                    443:     Always FALSE.
                    444: 
                    445: --*/
                    446: 
                    447: {
                    448: 
                    449:     PSERIAL_DEVICE_EXTENSION Extension = Context;
                    450: 
                    451:     SerialDump(
                    452:         SERDIAG3,
                    453:         ("SERIAL: In SerialGiveWaitToIsr\n")
                    454:         );
                    455:     //
                    456:     // There certainly shouldn't be a current mask location at
                    457:     // this point since we have a new current wait irp.
                    458:     //
                    459: 
                    460:     ASSERT(!Extension->IrpMaskLocation);
                    461: 
                    462:     //
                    463:     // The isr may or may not actually reference this irp.  It
                    464:     // won't if the wait can be satisfied immediately.  However,
                    465:     // since it will then go through the normal completion sequence,
                    466:     // we need to have an incremented reference count anyway.
                    467:     //
                    468: 
                    469:     SERIAL_INC_REFERENCE(Extension->CurrentWaitIrp);
                    470: 
                    471:     if (!Extension->HistoryMask) {
                    472: 
                    473:         SerialDump(
                    474:             SERDIAG4,
                    475:             ("SERIAL: No events occured prior to the wait call\n")
                    476:             );
                    477: 
                    478:         //
                    479:         // Although this wait might not be for empty transmit
                    480:         // queue, it doesn't hurt anything to set it to false.
                    481:         //
                    482: 
                    483:         Extension->EmptiedTransmit = FALSE;
                    484: 
                    485:         //
                    486:         // Record where the "completion mask" should be set.
                    487:         //
                    488: 
                    489:         Extension->IrpMaskLocation =
                    490:             Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer;
                    491:         SerialDump(
                    492:             SERDIAG4,
                    493:             ("SERIAL: The isr owns the irp %x, mask location is %x\n"
                    494:              "------- and system buffer is %x\n",
                    495:              Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
                    496:              Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer)
                    497:             );
                    498: 
                    499:     } else {
                    500: 
                    501:         SerialDump(
                    502:             SERDIAG4,
                    503:             ("SERIAL: %x occurred prior to the wait - starting the\n"
                    504:              "------- completion code for %x\n",
                    505:              Extension->HistoryMask,Extension->CurrentWaitIrp)
                    506:             );
                    507:         *((ULONG *)Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer) =
                    508:             Extension->HistoryMask;
                    509:         Extension->HistoryMask = 0;
                    510:         Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
                    511:         Extension->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
                    512: 
                    513:         KeInsertQueueDpc(
                    514:             &Extension->CommWaitDpc,
                    515:             NULL,
                    516:             NULL
                    517:             );
                    518: 
                    519:     }
                    520: 
                    521:     return FALSE;
                    522: }
                    523: 
                    524: BOOLEAN
                    525: SerialFinishOldWait(
                    526:     IN PVOID Context
                    527:     )
                    528: 
                    529: /*++
                    530: 
                    531: Routine Description:
                    532: 
                    533:     This routine will check to see if the ISR still knows about
                    534:     a wait irp by checking to see if the Irpmasklocation is non-null.
                    535:     If it is then it will zero the Irpmasklocation (which in effect
                    536:     grabs the irp away from the isr).  This routine is only called
                    537:     buy the cancel code for the wait.
                    538: 
                    539:     NOTE: This is called by KeSynchronizeExecution.
                    540: 
                    541: Arguments:
                    542: 
                    543:     Context - A pointer to the device extension
                    544: 
                    545: Return Value:
                    546: 
                    547:     Always FALSE.
                    548: 
                    549: --*/
                    550: 
                    551: {
                    552: 
                    553:     PSERIAL_DEVICE_EXTENSION Extension = Context;
                    554: 
                    555:     SerialDump(
                    556:         SERDIAG3,
                    557:         ("SERIAL: In SerialFinishOldWait\n")
                    558:         );
                    559:     if (Extension->IrpMaskLocation) {
                    560: 
                    561:         SerialDump(
                    562:             SERDIAG4,
                    563:             ("SERIAL: The isr still owns the irp %x, mask location is %x\n"
                    564:              "------- and system buffer is %x\n",
                    565:              Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
                    566:              Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer)
                    567:             );
                    568:         //
                    569:         // The isr still "owns" the irp.
                    570:         //
                    571: 
                    572:         *Extension->IrpMaskLocation = 0;
                    573:         Extension->IrpMaskLocation = NULL;
                    574: 
                    575:         Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
                    576: 
                    577:         //
                    578:         // We don't decrement the reference since the completion routine
                    579:         // will do that.
                    580:         //
                    581: 
                    582:         KeInsertQueueDpc(
                    583:             &Extension->CommWaitDpc,
                    584:             NULL,
                    585:             NULL
                    586:             );
                    587: 
                    588:     }
                    589: 
                    590:     //
                    591:     // Don't wipe out any historical data we are still interested in.
                    592:     //
                    593: 
                    594:     Extension->HistoryMask &= *((ULONG *)Extension->CurrentMaskIrp->
                    595:                                             AssociatedIrp.SystemBuffer);
                    596: 
                    597:     Extension->IsrWaitMask = *((ULONG *)Extension->CurrentMaskIrp->
                    598:                                             AssociatedIrp.SystemBuffer);
                    599:     SerialDump(
                    600:         SERDIAG4,
                    601:         ("SERIAL: Set mask location of %x, in irp %x, with system buffer of %x\n",
                    602:          Extension->IrpMaskLocation,
                    603:          Extension->CurrentMaskIrp,Extension->CurrentMaskIrp->AssociatedIrp.SystemBuffer)
                    604:         );
                    605:     return FALSE;
                    606: }
                    607: 
                    608: VOID
                    609: SerialCancelWait(
                    610:     IN PDEVICE_OBJECT DeviceObject,
                    611:     IN PIRP Irp
                    612:     )
                    613: 
                    614: /*++
                    615: 
                    616: Routine Description:
                    617: 
                    618:     This routine is used to cancel a irp that is waiting on
                    619:     a comm event.
                    620: 
                    621: Arguments:
                    622: 
                    623:     DeviceObject - Pointer to the device object for this device
                    624: 
                    625:     Irp - Pointer to the IRP for the current request
                    626: 
                    627: Return Value:
                    628: 
                    629:     None.
                    630: 
                    631: --*/
                    632: 
                    633: {
                    634: 
                    635:     PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
                    636: 
                    637:     SerialDump(
                    638:         SERDIAG3,
                    639:         ("SERIAL: In SerialCancelWait\n")
                    640:         );
                    641: 
                    642:     SerialDump(
                    643:         SERDIAG4,
                    644:         ("SERIAL: Canceling wait for irp %x\n",Extension->CurrentWaitIrp)
                    645:         );
                    646:     SerialTryToCompleteCurrent(
                    647:         Extension,
                    648:         SerialGrabWaitFromIsr,
                    649:         Irp->CancelIrql,
                    650:         STATUS_CANCELLED,
                    651:         &Extension->CurrentWaitIrp,
                    652:         NULL,
                    653:         NULL,
                    654:         NULL,
                    655:         NULL,
                    656:         NULL
                    657:         );
                    658: 
                    659: }
                    660: 
                    661: VOID
                    662: SerialCompleteWait(
                    663:     IN PKDPC Dpc,
                    664:     IN PVOID DeferredContext,
                    665:     IN PVOID SystemContext1,
                    666:     IN PVOID SystemContext2
                    667:     )
                    668: 
                    669: {
                    670: 
                    671:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
                    672:     KIRQL OldIrql;
                    673: 
                    674:     SerialDump(
                    675:         SERDIAG3,
                    676:         ("SERIAL: In SerialCompleteWait\n")
                    677:         );
                    678:     UNREFERENCED_PARAMETER(Dpc);
                    679:     UNREFERENCED_PARAMETER(SystemContext1);
                    680:     UNREFERENCED_PARAMETER(SystemContext2);
                    681: 
                    682:     IoAcquireCancelSpinLock(&OldIrql);
                    683: 
                    684:     SerialDump(
                    685:         SERDIAG4,
                    686:         ("SERIAL: Completing wait for irp %x\n",Extension->CurrentWaitIrp)
                    687:         );
                    688:     SerialTryToCompleteCurrent(
                    689:         Extension,
                    690:         NULL,
                    691:         OldIrql,
                    692:         STATUS_SUCCESS,
                    693:         &Extension->CurrentWaitIrp,
                    694:         NULL,
                    695:         NULL,
                    696:         NULL,
                    697:         NULL,
                    698:         NULL
                    699:         );
                    700: 
                    701: }

unix.superglobalmegacorp.com

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