/*static char *SCCSID = "@(#)closeq.c   6.2 91/03/29";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*
 *      This code will implement DosCloseQueue
 */

#include        <error.h>
#include        <error2.h>
#include        <doscalls.h>
#include        <infoseg.h>
#include        <ipcqueue.h>

/* Defect 66858  added queue offset parameter to L_Delete  D.B. */
unsigned int L_Delete(unsigned int, struct Q_ENTRY far *, struct L_ENTRY far *, struct L_ENTRY far *);

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SOURCE FILE NAME:   closeq.c                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   DosCloseQueue                                */
/*                                                                  */
/* STATUS: RELEASE 1 LEVEL 0                                        */
/*                                                                  */
/* FUNCTION:   Closes a queue for the requesting process, or        */
/*             deletes a queue for the owning process.              */
/*                                                                  */
/* NOTES:                                                           */
/*    DEPENDENCIES:                                                 */
/*    RESTRICTIONS:                                                 */
/*                                                                  */
/* ENTRY POINTS:       DosCloseQueue                                */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*             Close16EventSem:FAR                                  */
/*             FuncInit:NEAR                                        */
/*             FuncFree:NEAR                                        */
/*             L_Remove:NEAR                                        */
/*             Q_Delete:NEAR                                        */
/*             Q_Scan:NEAR                                          */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

#if defined(MMIOPH)
extern void queues_sys_trace(
unsigned,                                       /* que_major_code */
unsigned,                                       /* int que_data_len */
unsigned,                                       /* que_minor_code */
char far *);                                    /* que_data */
#endif

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    L_Delete                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   L_Delete                                     */
/*                                                                  */
/* FUNCTION:   Delete the appropriate link for the requesting proc. */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        L_Delete                                     */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*             DW      queue handle of desired link                 */
/*             DD      offset of desired queue                      */
/*             DD      offset of desired link                       */
/*             DD      offset of previous link                      */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    Update link count, remove if necessary               */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             L_Remove:NEAR                                        */
/*             Close16EventSem:FAR                                  */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      L_Delete:                                                   */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*     Decrement the link count if more than one link between this  */
/*process and this queue, else delete the link.                     */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/*        if (offset.l_cnt < 2)                                     */
/*          if wait semaphore opened                                */
/*            call Close16EventSem to perform                       */
/*                 Dos32CloseEventSem on the wait semaphore         */
/*          call L_Remove                                           */
/*          if (L_Remove returns in error) then                     */
/*            set error code    from L_REMOVE                       */
/*          else                                                    */
/*            set good return                                       */
/*          endif                                                   */
/*        else                                                      */
/*          decrement offset.l_cnt                                  */
/*          set good return                                         */
/*        endif                                                     */
/*       return                                                     */

/*********/
extern unsigned far CLOSE16EVENTSEM(unsigned long);
/*********/

unsigned int
L_Delete(qhndl,qoff,loff,lprev)
register unsigned int qhndl;
struct  Q_ENTRY far *qoff;
struct  L_ENTRY far *loff;
struct  L_ENTRY far *lprev;
{
        extern  struct  STATDATA        statseg;
        register unsigned int rc;

        if ((*loff).l_cnt < 2)
        {
                if ((*loff).l_flags & S_OPENED)
                        CLOSE16EVENTSEM((*qoff).q_semhnd);
                rc = L_Remove(loff,lprev,qhndl);
        }
        else
        {
                (*loff).l_cnt--;
                rc = NO_ERROR;
        }
        return(rc);
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    DosCloseQueue                                */
/*                                                                  */
/* DESCRIPTIVE NAME:   DosCloseQueue                                */
/*                                                                  */
/* FUNCTION:   Main line control for DosCloseQueue function         */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        DosCloseQueue                                */
/*    LINKAGE:         far at pl 2                                  */
/*                                                                  */
/* INPUT:                                                           */
/*             DW      Queue Handle                                 */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'INVALID QUEUE HANDLE'                               */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    Deletes queue and elements for owner,                */
/*             removes link for nonowner                            */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             L_Delete:NEAR                                        */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             queues_sys_trace:NEAR                                */
/*             FuncFree:NEAR                                        */
/*             FuncInit:NEAR                                        */
/*             L_Find:NEAR                                          */
/*             Q_Delete:NEAR                                        */
/*             Q_Scan:NEAR                                          */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*                                                                  */
/********************************************************************/
/*                                                                  */
/*This acts as the entry point and main line control for            */
/*DosCloseQueue. After initialization, it attempts to find the named*/
/*queue. If the named queue's PID matches the current PID, a routine*/
/*will perform logic to delete the queue.If queue PID does not match*/
/*current PID,routines will be called to find and delete the link to*/
/*the named queue.                                                  */
/*                                                                  */
/********************************************************************/
/*                                                                  */
/* DosCloseQueue:                                                   */
/*                                                                  */
/*      initialize error                'NO ERROR'                  */
/*      if (tracing active)                                         */
/*        call queues_sys_trace                                     */
/*      endif                                                       */
/*      call FuncInit                                               */
/*      if (FuncInit returns in error) then                         */
/*        set error code        'SYS ERROR'                         */
/*      else                                                        */
/*        call Q_Scan                                               */
/*        if (Q_Scan returns in error) then                         */
/*          set error code      'INVALID QUEUE HANDLE'              */
/*        else                                                      */
/*          call L_Find                                             */
/*          if (L_Find returns in error) then                       */
/*            set error code  from L_Find                           */
/*          else                                                    */
/*            call L_Delete                                         */
/*            set return code from L_Delete                         */
/*          endif                                                   */
/*          if (no error)                                           */
/*            if (qu_entry.q_pid = static.st_pid) then              */
/*              call Q_Delete                                       */
/*              if (Q_Delete returns in error) then                 */
/*                set error code  'SYS ERROR'                       */
/*              endif                                               */
/*            endif                                                 */
/*          endif                                                   */
/*        endif                                                     */
/*        call FuncFree                                             */
/*        if (FuncFree returns in error and error not set)          */
/*          set error code        'SYS ERROR'                       */
/*        endif                                                     */
/*      endif                                                       */
/*      if (tracing active)                                         */
/*        call queues_sys_trace                                     */
/*      endif                                                       */
/*      return                                                      */

unsigned far pascal
DOSCLOSEQUEUE(QHnd)
register unsigned QHnd;
{
        extern  struct  InfoSegGDT far  *globptr;
        extern  struct  STATDATA        statseg;
        struct  Q_ENTRY far *q_offset;
        struct  Q_ENTRY far *q_prev;
        struct  L_ENTRY far *l_offset;
        struct  L_ENTRY far *l_prev;
        register unsigned int rc;
#if defined(MMIOPH)
        struct RAS_PRE_CLOSE {
                unsigned long rp_hnd;
        } ras_pre_close;
        struct RAS_POST_CLOSE {
                unsigned long rp_rc;
        } ras_post_close;
#endif

        PUSHALL_DS();
        rc = NO_ERROR;
        #if (cdbug)
        krnldbug();
        #endif

/***DT DosCloseQueue - Pre-Invocation Dynamic Trace
 *     TRACE MINOR =0x0001,
 *           TP=@
 *           TYPE  =(PRE,API),
 *           DESC  ="(OS) DosCloseQueue Pre-Invocation",
 *           FMT   ="Handle=%pw",
 *           MEM   =(.QHnd,d,2)
 */

#if defined(MMIOPH)
        if (((*globptr).mec_table[17] & 0x80) != NULL)
        {
                ras_pre_close.rp_hnd = (unsigned long)QHnd;
                queues_sys_trace(((unsigned) 0x88),sizeof(struct RAS_PRE_CLOSE),((unsigned) 1),(char far *) &ras_pre_close);
        }
#endif

        if ((FuncInit()) != NO_ERROR)
                rc = ERROR_SYS_INTERNAL;
        else
        {
                if ((rc = Q_Scan((struct Q_ENTRY far * far *) &q_offset,(struct Q_ENTRY far * far *) &q_prev,QHnd)) == NO_ERROR)
                {
                        if ((L_Find(QHnd,(struct L_ENTRY far * far *) &l_offset,(struct L_ENTRY far * far *) &l_prev)) == NO_ERROR)
                                rc = L_Delete(QHnd,q_offset,l_offset,l_prev);
                        if (rc == NO_ERROR)
                        {
                                if ((*q_offset).q_pid == statseg.st_pid)
                                {
                                        if ((Q_Delete(q_offset,q_prev)) != NO_ERROR)
                                                rc = ERROR_SYS_INTERNAL;
                                }
                        }
                }
                if ((FuncFree() != NO_ERROR) && (rc == NO_ERROR))
                        rc = ERROR_SYS_INTERNAL;
        }

/***DT DosCloseQueue - Post-Invocation Dynamic Trace
 *     TRACE MINOR =0x8001,
 *           TP=@
 *           TYPE  =(POST,API),
 *           DESC  ="(OS) DosCloseQueue Post-Invocation",
 *           FMT   ="Return Code=%pw",
 *           MEM   =(.rc,d,2)
 */

#if defined(MMIOPH)
        if (((*globptr).mec_table[17] & 0x80) != NULL)
        {
                ras_post_close.rp_rc = (unsigned long)rc;
                queues_sys_trace(((unsigned) 0x88),sizeof(struct RAS_POST_CLOSE),((unsigned) 0x81),(char far *) &ras_post_close);
        }
#endif

        return(POPALL(rc));
}
