/*static char *SCCSID = "@(#)exitlstq.c 6.2 90/12/05";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*
 *      This code will implement ExitListQueue
 */

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

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SOURCE FILE NAME:   exitlstq.c                                   */
/*                                                                  */
/* DESCRIPTIVE NAME:   ExitListQueue                                */
/*                                                                  */
/* STATUS: RELEASE 1 LEVEL 0                                        */
/*                                                                  */
/* FUNCTION:   exitlist calls for ipc queues                        */
/*                                                                  */
/* NOTES:                                                           */
/*    DEPENDENCIES:                                                 */
/*    RESTRICTIONS:                                                 */
/*                                                                  */
/* ENTRY POINTS:       C_EXITLISTQUEUE1                             */
/*                     C_EXITLISTQUEUE2                             */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSCLOSESEM:FAR                                      */
/*             DOSEXITLIST:FAR                                      */
/*             FuncFree:NEAR                                        */
/*             L_Remove:NEAR                                        */
/*             Q_Delete:NEAR                                        */
/*                                                                  */
/*                   Modification Log                               */
/*  Date   Name   Description                                       */
/* 4/4/10  ChangeTeam Added check for ERROR_TOO_MANY_POSTS          */
/*                    Defect : 118139                               */
/*********************** END OF SPECIFICATIONS **********************/

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    C_EXITLISTQUEUE1                             */
/*                                                                  */
/* DESCRIPTIVE NAME:   C_EXITLISTQUEUE1                             */
/*                                                                  */
/* FUNCTION:   Main line control for ExitListQueue1                 */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        C_EXITLISTQUEUE1                             */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             N/A                                                  */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             N/A                                                  */
/*                                                                  */
/* EFFECTS:                                                         */
/*             Put queue data into steady state so that system      */
/*                 semaphores will not be needed                    */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSEXITLIST:FAR                                      */
/*             FuncFree:NEAR                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      C_EXITLISTQUEUE1:                                           */
/*                                                                  */
/*      call DosSemrequest                                          */
/*      if (no error or owner died)                                 */
/*        set error code                'NO ERROR'                  */
/*        set pid                                                   */
/*        if (exitlist action flag set)                             */
/*          perform appropriate action case to insure data          */
/*                 structure integrity                              */
/*          set exitlist action flag off                            */
/*        endif                                                     */
/*      endif                                                       */
/*      call FuncFree                                               */
/*      exit via DoseExitList, function 3                           */


/*      Pointers for Action Processing  */

        unsigned char   action = 0;
        unsigned count = 0;
        struct  Q_ENTRY far *prev_fst_q = 0;
        struct  L_ENTRY far *prev_fst_link = 0;
        struct  Q_ENTRY far *que1 = 0;
        struct  Q_ENTRY far *que2 = 0;
        struct  Q_ENTRY far *que3 = 0;
        struct  L_ENTRY far *lnk1 = 0;
        struct  L_ENTRY far *lnk2 = 0;
        struct  L_ENTRY far *lnk3 = 0;
        struct  E_ENTRY far *emt1 = 0;
        struct  E_ENTRY far *emt2 = 0;
        struct  E_ENTRY far *emt3 = 0;

void far pascal
C_EXITLISTQUEUE1()
{
        extern  struct  STATDATA        statseg;
        extern  struct  Q_INST  far *ISEG;
        extern  unsigned char   action;
        extern  unsigned count;
        extern  struct  Q_ENTRY far *prev_fst_q;
        extern  struct  L_ENTRY far *prev_fst_link;
        extern  struct  Q_ENTRY far *que1;
        extern  struct  Q_ENTRY far *que2;
        extern  struct  Q_ENTRY far *que3;
        extern  struct  L_ENTRY far *lnk1;
        extern  struct  L_ENTRY far *lnk2;
        extern  struct  L_ENTRY far *lnk3;
        extern  struct  E_ENTRY far *emt1;
        extern  struct  E_ENTRY far *emt2;
        extern  struct  E_ENTRY far *emt3;
        struct  L_ENTRY far     *loffset;
        struct  L_ENTRY far     *lprev;
        struct  L_ENTRY far     *lnext;
        struct  Q_ENTRY far     *qoffset;
        struct  Q_ENTRY far     *qprev;
        struct  Q_ENTRY far     *qnext;
        extern  void far EXITLISTQUEUE1 (void);
        extern  unsigned far POST16EVENTSEM(unsigned long);

        register unsigned int    qhandl;
        register unsigned int    rc;


        PUSHALL_DS();
        #if (cdbug)
        krnldbug();
        #endif
        rc = DOSSEMREQUEST((*ISEG).inst_semhnd,((unsigned long) -1));
        if ((rc == NO_ERROR) || (rc == ERROR_SEM_OWNER_DIED))
        {
                rc = NO_ERROR;
                statseg.st_pid = (*ISEG).inst_pid;
                switch(action)
                {
                        case ACT_ADD_QUE:
                                statseg.fst_q = que1;
                                break;
                        case ACT_ADD_LNK:
                                (*que1).q_flags |= Q_LINKS;
                                statseg.fst_link = lnk1;
                                break;
                        case ACT_DEL_ONLY_EMT:
                                (*que1).q_fst = NULL;
                                (*que1).q_lst = NULL;
                                (*que1).q_cnt = NULL;
                                DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                break;
                        case ACT_DEL_FST_EMT:
                                (*que1).q_fst = emt3;
                                (*emt3).e_prev = NULL;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt--;
                                DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                break;
                        case ACT_DEL_LST_EMT:
                                (*que1).q_lst = emt2;
                                (*emt2).e_next = NULL;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt--;
                                DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                break;
                        case ACT_DEL_MID_EMT:
                                (*emt2).e_next = emt3;
                                (*emt3).e_prev = emt2;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt--;
                                DOSSUBFREE(FP_SEG(emt1),FP_OFF(emt1),sizeof(struct E_ENTRY));
                                break;
                        case ACT_DEL_LNK:
                                if (prev_fst_link == lnk1)
                                        statseg.fst_link = lnk3;
                                else
                                        (*lnk2).l_chain = lnk3;
                                DOSSUBFREE(FP_SEG(lnk1),FP_OFF(lnk1),sizeof(struct L_ENTRY));
                                break;
                        case ACT_ADD_ONLY_EMT:
                                (*que1).q_fst = emt1;
                                (*que1).q_lst = emt1;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt++;

                                if (DOSSEMWAIT((unsigned long)&((*que1).q_ramsem),0l)==NO_ERROR)   /*no one waiting, clear the wait sem*/
                                {
                                    if ((*que1).q_semhnd != 0)
                                    {
                                        /* if function called from 16-bit code */
                                        if (((*que1).q_flags & Q_BIT32) == 0)
                                        {
                                          if ((DOSSEMCLEAR((*que1).q_semhnd)) != NO_ERROR)
                                          {
                                              rc = ERROR_SYS_INTERNAL;
                                          } /* endif */
                                        } /* endif */
                                        /* else function was called from 32-bit code */
                                        else
                                        {
                                           /* call thunk to call Dos32PostEventSem */
                                           rc = POST16EVENTSEM((*que1).q_semhnd);
                                           if (rc != NO_ERROR)
                                           {
                                              /* if semaphore had already been posted (cleared) */
                                              /* if (rc == ERROR_ALREADY_POSTED)       D118139 - Commented out */
                                              if ( ( rc == ERROR_ALREADY_POSTED) || ( rc == ERROR_TOO_MANY_POSTS ) )  /* D118139 */
                                              {
                                                 /* that is not an error */
                                                 rc = NO_ERROR;
                                              }
                                              else
                                              {
                                                 rc = ERROR_SYS_INTERNAL;
                                              } /* endif */
                                           }
                                        } /* end elseif */
                                    }
                                }

                                break;
                        case ACT_ADD_LST_EMT:
                                (*que1).q_lst = emt1;
                                (*emt2).e_next = emt1;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt++;
                                break;
                        case ACT_ADD_FST_EMT:
                                (*que1).q_fst = emt1;
                                (*emt2).e_prev = emt1;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt++;
                                break;
                        case ACT_ADD_MID_EMT:
                                (*emt3).e_prev = emt1;
                                (*emt2).e_next = emt1;
                                if ((*que1).q_cnt == count)
                                        (*que1).q_cnt++;
                                break;
                        case ACT_DEL_QUE:
                                if (prev_fst_q == que1)
                                        statseg.fst_q = que3;
                                else
                                        (*que2).q_chain = que3;
                                DOSSUBFREE(FP_SEG(que1),FP_OFF(que1),(sizeof(struct Q_ENTRY)+farstrlen((*que1).q_name)));
                                break;
                        case 0:
                        default:
                                break;
                }
        }
        FuncFree();
        POPALL(0);
        DOSEXITLIST(((unsigned) 3),EXITLISTQUEUE1);
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    C_EXITLISTQUEUE2                             */
/*                                                                  */
/* DESCRIPTIVE NAME:   C_EXITLISTQUEUE2                             */
/*                                                                  */
/* FUNCTION:   Main line control for ExitListQueue2                 */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        C_EXITLISTQUEUE2                             */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             N/A                                                  */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             N/A                                                  */
/*                                                                  */
/* EFFECTS:                                                         */
/*             Deletes queue and link entries for the pid, and      */
/*             will adjust other queues and links accordingly.      */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSCLOSESEM:FAR                                      */
/*             DOSEXITLIST:FAR                                      */
/*             FuncFree:NEAR                                        */
/*             L_Remove:NEAR                                        */
/*             Q_Delete:NEAR                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      C_EXITLISTQUEUE2:                                           */
/*                                                                  */
/*      call DosSemrequest                                          */
/*      if (no error or owner died)                                 */
/*        set error code                'NO ERROR'                  */
/*        set pid                                                   */
/*        set loffset = static.fst_lnk                              */
/*        set lprev = NULL                                          */
/*        if (loffset != NULL) then                                 */
/*          while (loffset != NULL & no error) do                   */
/*            if (loffset.l_pid = static.st_pid) then               */
/*              lnext = loffset.l_chain                             */
/*              call L_Remove                                       */
/*              loffset = lnext                                     */
/*            else                                                  */
/*              lprev = loffset                                     */
/*              loffset = loffset.l_chain                           */
/*            endif                                                 */
/*          endwhile                                                */
/*        endif                                                     */
/*        if (no error) then                                        */
/*          set qu_entry = static.fst_q                             */
/*          set qprev = NULL                                        */
/*          while (qu_entry != NULL & no error) do                  */
/*            if (qu_entry.q_pid = static.st_pid) then              */
/*              qnext = qu_entry.q_chain                            */
/*              call Q_Delete                                       */
/*              qu_entry = qnext                                    */
/*            else                                                  */
/*              qprev = qu_entry                                    */
/*              qu_entry = qu_entry.q_chain                         */
/*            endif                                                 */
/*          endwhile                                                */
/*        endif                                                     */
/*      endif                                                       */
/*      call FuncFree                                               */
/*      call DosCloseSem                                            */
/*      clear inst_semhnd                                           */
/*      exit via DoseExitList, function 3                           */

void far pascal
C_EXITLISTQUEUE2()
{
        extern  struct  STATDATA        statseg;
        extern  struct  Q_INST  far *ISEG;
        extern  unsigned char   action;
        extern  unsigned count;
        extern  struct  Q_ENTRY far *prev_fst_q;
        extern  struct  L_ENTRY far *prev_fst_link;
        extern  struct  Q_ENTRY far *que1;
        extern  struct  Q_ENTRY far *que2;
        extern  struct  Q_ENTRY far *que3;
        extern  struct  L_ENTRY far *lnk1;
        extern  struct  L_ENTRY far *lnk2;
        extern  struct  L_ENTRY far *lnk3;
        extern  struct  E_ENTRY far *emt1;
        extern  struct  E_ENTRY far *emt2;
        extern  struct  E_ENTRY far *emt3;
        struct  L_ENTRY far     *loffset;
        struct  L_ENTRY far     *lprev;
        struct  L_ENTRY far     *lnext;
        struct  Q_ENTRY far     *qoffset;
        struct  Q_ENTRY far     *qprev;
        struct  Q_ENTRY far     *qnext;
        extern  void far EXITLISTQUEUE2 (void);

        register unsigned int    qhandl;
        register unsigned int    rc;


        PUSHALL_DS();
        #if (cdbug)
        krnldbug();
        #endif
        rc = DOSSEMREQUEST((*ISEG).inst_semhnd,((unsigned long) -1));
        if ((rc == NO_ERROR) || (rc == ERROR_SEM_OWNER_DIED))
        {
                rc = NO_ERROR;
                statseg.st_pid = (*ISEG).inst_pid;

                action = 0;
                loffset = statseg.fst_link;
                lprev = NULL;
                if (loffset != NULL)
                {
                        while ((loffset != NULL) && (rc == NO_ERROR))
                        {
                                if ((*loffset).l_pid == statseg.st_pid)
                                {
                                        qhandl = (*loffset).l_qhndl;
                                        lnext = (*loffset).l_chain;
                                        rc = L_Remove(loffset,lprev,qhandl);
                                        loffset = lnext;
                                }
                                else
                                {
                                        lprev = loffset;
                                        loffset = (*loffset).l_chain;
                                }
                        }
                }
                if (rc == NO_ERROR)
                {
                        qoffset = statseg.fst_q;
                        qprev = NULL;
                        if (qoffset != NULL)
                        {
                                while ((qoffset != NULL) && (rc == NO_ERROR))
                                {
                                        if ((*qoffset).q_pid == statseg.st_pid)
                                        {
                                                qnext = (*qoffset).q_chain;
                                                rc = Q_Delete(qoffset,qprev);
                                                qoffset = qnext;
                                        }
                                        else
                                        {
                                                qprev = qoffset;
                                                qoffset = (*qoffset).q_chain;
                                        }
                                }
                        }
                }
        }
        FuncFree();
        DOSCLOSESEM((*ISEG).inst_semhnd);
        (*ISEG).inst_semhnd = NULL;
        POPALL(0);
        DOSEXITLIST(((unsigned) 3),EXITLISTQUEUE2);
}
