/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  $Id: ix_close.c,v 1.6 1992/10/20 16:18:58 mwild Exp mwild $
 *
 *  $Log: ix_close.c,v $
 *  Revision 1.6  1992/10/20  16:18:58  mwild
 *  moved closing of files out before Forbid (ix_startup, vfork)
 *  possibly free a4 databss-segment here (see ix_resident.c)
 *
 *  Revision 1.5  1992/08/09  20:46:42  amiga
 *  delay restoring of old handlers
 *
 *  Revision 1.4  1992/07/04  19:12:12  mwild
 *  don't just free death-messages, wake any children possibly waiting on them
 *
 * Revision 1.3  1992/05/22  01:44:17  mwild
 * when debugging, check whether buddy allocator clean
 *
 * Revision 1.2  1992/05/18  12:18:00  mwild
 * changed async mp to be global
 *
 * Revision 1.1  1992/05/14  19:55:40  mwild
 * Initial revision
 *
 */

#define KERNEL
#include "ixemul.h"
#undef u
#undef ix
#include <hardware/intbits.h>

/* #undef DEBUG */

#ifdef DEBUG
#define DP(a) kprintf a
#else
#define DP(a)
#endif

#define BASE_EXT_DECL
#define BASE_PAR_DECL	struct ixemul_base *ix,
#define BASE_PAR_DECL0	struct ixemul_base *ix
#define BASE_NAME	ix->ix_intui_base
#include <inline/intuition.h>

extern struct ExecBase 	*SysBase;

void
ix_close (struct ixemul_base *ixbase)
{
  int fd;
  struct Task 		*me 	 =	SysBase->ThisTask;
  struct user 		*u	 =	(struct user *) me->tc_TrapData;
  struct Process	*child;
  struct user		*cu;
  struct Node		*dm, *ndm;	/* really struct death_msg * */

DP(("ix_close.\n"));
    
  RemIntServer (INTB_VERTB, & u->u_itimerint);  
#if later
#endif
  
  /* already reset the trap vector here. It's better to get an alert, than
   * to loop infinitely if one of the following functions should crash */
  me->tc_TrapCode = u->u_otrap_code;

  /* had to move this block after the SYS_close's, since close() might have
     to wait for a packet, and then it's essential that our switch/launch
     handlers are still active, or curproc is not updated accordingly */
  me->tc_Flags    = u->u_otask_flags;
  me->tc_Launch	  = u->u_olaunch;
  me->tc_Switch   = u->u_oswitch;
  FreeSignal (u->u_sleep_sig);

  CloseDevice ((struct IORequest *) u->u_time_req);
  syscall (SYS_DeleteExtIO, u->u_time_req);
  
  if (u->u_startup_cd != (BPTR) -1) __unlock (CurrentDir (u->u_startup_cd));

  u->u_trace_flags = 1;
  DeletePort (u->u_sync_mp);
#if 0
  /* see ix_open.c */
  DeleteInterruptPort (u->u_async_mp);
#endif

#if 0
  /* can't do this here, we're inside Forbid and if ix_lock_base would block,
     the Forbid would be broken */

  /* have to make sure that no child is trying to manipulate our process
   * lists as well */
  ix_lock_base ();
#endif
  
  for ((child = u->p_cptr) && (cu = (struct user *) (child->pr_Task.tc_TrapData));
       child;
       (child = cu->p_osptr) && (cu = (struct user *) (child->pr_Task.tc_TrapData)))
    cu->p_pptr = (struct Process *) 1;

  u->p_cptr = 0;
  
  for (dm  = (struct Node *) u->p_zombies.mlh_Head;
       ndm = dm->ln_Succ;
       dm  = ndm)
    {
      /* there might be children sleeping on this, so wake them up now.. */
      ix_wakeup (dm);
      kfree (dm);
    }

#if 0
  ix_unlock_base ();
#endif

  FreeSignal (u->p_zombie_sig);

  all_free ();
  if (u->p_flag & SFREEA4)
    kfree (u->u_a4 - 0x7ffe);

#ifdef DEBUG
/*  check_empty (0);*/
#endif

  /* delay this until here, since the above called functions need access
   * to the user area. */
  me->tc_TrapData = u->u_otrap_data;

  kfree (u);
}
