/* do not edit automatically generated by mc from RTint.  */
/* RTint.mod provides users of the COROUTINES library with the.

Copyright (C) 2009-2025 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 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
General Public License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "GStorage.h"
#   include "Gmcrts.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _RTint_C

#include "GRTint.h"
#   include "GM2RTS.h"
#   include "GStorage.h"
#   include "GRTco.h"
#   include "GCOROUTINES.h"
#   include "Glibc.h"
#   include "GAssertion.h"
#   include "GSelective.h"

typedef struct RTint_DispatchVector_p RTint_DispatchVector;

#   define Microseconds 1000000
#   define DebugTime 0
#   define Debugging false
typedef struct RTint__T1_r RTint__T1;

typedef RTint__T1 *RTint_Vector;

typedef struct RTint__T2_a RTint__T2;

typedef enum {RTint_input, RTint_output, RTint_time} RTint_VectorType;

struct RTint__T1_r {
                     RTint_VectorType type;
                     unsigned int priority;
                     void * arg;
                     RTint_Vector pending;
                     RTint_Vector exists;
                     unsigned int no;
                     int File;
                     Selective_Timeval rel;
                     Selective_Timeval abs_;
                     bool queued;
                   };

struct RTint__T2_a { RTint_Vector array[(7)-(COROUTINES_UnassignedPriority)+1]; };
static unsigned int VecNo;
static RTint_Vector Exists;
static RTint__T2 Pending;
static int lock;
static bool initialized;

/*
   InitInputVector - returns an interrupt vector which is associated
                     with the file descriptor, fd.
*/

extern "C" unsigned int RTint_InitInputVector (int fd, unsigned int pri);

/*
   InitOutputVector - returns an interrupt vector which is associated
                      with the file descriptor, fd.
*/

extern "C" unsigned int RTint_InitOutputVector (int fd, unsigned int pri);

/*
   InitTimeVector - returns an interrupt vector associated with
                    the relative time.
*/

extern "C" unsigned int RTint_InitTimeVector (unsigned int micro, unsigned int secs, unsigned int pri);

/*
   ReArmTimeVector - reprimes the vector, vec, to deliver an interrupt
                     at the new relative time.
*/

extern "C" void RTint_ReArmTimeVector (unsigned int vec, unsigned int micro, unsigned int secs);

/*
   GetTimeVector - assigns, micro, and, secs, with the remaining
                   time before this interrupt will expire.
                   This value is only updated when a Listen
                   occurs.
*/

extern "C" void RTint_GetTimeVector (unsigned int vec, unsigned int *micro, unsigned int *secs);

/*
   AttachVector - adds the pointer ptr to be associated with the interrupt
                  vector. It returns the previous value attached to this
                  vector.
*/

extern "C" void * RTint_AttachVector (unsigned int vec, void * ptr);

/*
   IncludeVector - includes, vec, into the dispatcher list of
                   possible interrupt causes.
*/

extern "C" void RTint_IncludeVector (unsigned int vec);

/*
   ExcludeVector - excludes, vec, from the dispatcher list of
                   possible interrupt causes.
*/

extern "C" void RTint_ExcludeVector (unsigned int vec);

/*
   Listen - will either block indefinitely (until an interrupt)
            or alteratively will test to see whether any interrupts
            are pending.
            If a pending interrupt was found then, call, is called
            and then this procedure returns.
            It only listens for interrupts > pri.
*/

extern "C" void RTint_Listen (bool untilInterrupt, RTint_DispatchVector call, unsigned int pri);

/*
   Init -
*/

extern "C" void RTint_Init (void);

/*
   Max - returns the maximum: i or j.
*/

static int Max (int i, int j);
static int Min (int i, int j);

/*
   FindVector - searches the exists list for a vector of type
                which is associated with file descriptor, fd.
*/

static RTint_Vector FindVector (int fd, RTint_VectorType type);

/*
   FindVectorNo - searches the Exists list for vector vec.
*/

static RTint_Vector FindVectorNo (unsigned int vec);

/*
   FindPendingVector - searches the pending list for vector, vec.
*/

static RTint_Vector FindPendingVector (unsigned int vec);

/*
   AddFd - adds the file descriptor fd to set updating max.
*/

static void AddFd (Selective_SetOfFd *set, int *max, int fd);

/*
   DumpPendingQueue - displays the pending queue.
*/

static void DumpPendingQueue (void);

/*
   AddTime - t1 := t1 + t2
*/

static void AddTime (Selective_Timeval t1, Selective_Timeval t2);

/*
   IsGreaterEqual - returns TRUE if, a>=b
*/

static bool IsGreaterEqual (Selective_Timeval a, Selective_Timeval b);

/*
   SubTime - assigns, s and m, to a - b.
*/

static void SubTime (unsigned int *s, unsigned int *m, Selective_Timeval a, Selective_Timeval b);

/*
   activatePending - activates the first interrupt pending and clears it.
*/

static bool activatePending (bool untilInterrupt, RTint_DispatchVector call, unsigned int pri, int maxFd, Selective_SetOfFd *inSet, Selective_SetOfFd *outSet, Selective_Timeval *timeval, Selective_Timeval b4, Selective_Timeval after);

/*
   init -
*/

static void init (void);


/*
   Max - returns the maximum: i or j.
*/

static int Max (int i, int j)
{
  if (i > j)
    {
      return i;
    }
  else
    {
      return j;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

static int Min (int i, int j)
{
  /*
   Max - returns the minimum: i or j.
  */
  if (i < j)
    {
      return i;
    }
  else
    {
      return j;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindVector - searches the exists list for a vector of type
                which is associated with file descriptor, fd.
*/

static RTint_Vector FindVector (int fd, RTint_VectorType type)
{
  RTint_Vector vec;

  vec = Exists;
  while (vec != NULL)
    {
      if ((vec->type == type) && (vec->File == fd))
        {
          return vec;
        }
      vec = vec->exists;
    }
  return NULL;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindVectorNo - searches the Exists list for vector vec.
*/

static RTint_Vector FindVectorNo (unsigned int vec)
{
  RTint_Vector vptr;

  vptr = Exists;
  while ((vptr != NULL) && (vptr->no != vec))
    {
      vptr = vptr->exists;
    }
  return vptr;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindPendingVector - searches the pending list for vector, vec.
*/

static RTint_Vector FindPendingVector (unsigned int vec)
{
  unsigned int pri;
  RTint_Vector vptr;

  for (pri=COROUTINES_UnassignedPriority; pri<=7; pri++)
    {
      vptr = Pending.array[pri-(COROUTINES_UnassignedPriority)];
      while ((vptr != NULL) && (vptr->no != vec))
        {
          vptr = vptr->pending;
        }
      if ((vptr != NULL) && (vptr->no == vec))
        {
          return vptr;
        }
    }
  return NULL;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   AddFd - adds the file descriptor fd to set updating max.
*/

static void AddFd (Selective_SetOfFd *set, int *max, int fd)
{
  if (fd < 0)
    {
      return;
    }
  (*max) = Max (fd, (*max));
  if ((*set) == NULL)
    {
      (*set) = Selective_InitSet ();
      Selective_FdZero ((*set));
    }
  /* printf('%d, ', fd)  */
  Selective_FdSet (fd, (*set));
}


/*
   DumpPendingQueue - displays the pending queue.
*/

static void DumpPendingQueue (void)
{
  COROUTINES_PROTECTION pri;
  RTint_Vector vptr;
  unsigned int sec;
  unsigned int micro;

  libc_printf ((const char *) "Pending queue\\n", 15);
  for (pri=COROUTINES_UnassignedPriority; pri<=7; pri++)
    {
      libc_printf ((const char *) "[%d]  ", 6, pri);
      vptr = Pending.array[pri-(COROUTINES_UnassignedPriority)];
      while (vptr != NULL)
        {
          if ((vptr->type == RTint_input) || (vptr->type == RTint_output))
            {
              libc_printf ((const char *) "(fd=%d) (vec=%d)", 16, vptr->File, vptr->no);
            }
          else if (vptr->type == RTint_time)
            {
              /* avoid dangling else.  */
              Selective_GetTime (vptr->rel, &sec, &micro);
              Assertion_Assert (micro < Microseconds);
              libc_printf ((const char *) "time (%u.%06u secs) (arg = %p)\\n", 32, sec, micro, vptr->arg);
            }
          vptr = vptr->pending;
        }
      libc_printf ((const char *) " \\n", 3);
    }
}


/*
   AddTime - t1 := t1 + t2
*/

static void AddTime (Selective_Timeval t1, Selective_Timeval t2)
{
  unsigned int a;
  unsigned int b;
  unsigned int s;
  unsigned int m;

  Selective_GetTime (t1, &s, &m);
  Assertion_Assert (m < Microseconds);
  Selective_GetTime (t2, &a, &b);
  Assertion_Assert (b < Microseconds);
  a += s;
  b += m;
  if (b >= Microseconds)
    {
      b -= Microseconds;
      a += 1;
    }
  Selective_SetTime (t1, a, b);
}


/*
   IsGreaterEqual - returns TRUE if, a>=b
*/

static bool IsGreaterEqual (Selective_Timeval a, Selective_Timeval b)
{
  unsigned int as;
  unsigned int am;
  unsigned int bs;
  unsigned int bm;

  Selective_GetTime (a, &as, &am);
  Assertion_Assert (am < Microseconds);
  Selective_GetTime (b, &bs, &bm);
  Assertion_Assert (bm < Microseconds);
  return (as > bs) || ((as == bs) && (am >= bm));
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   SubTime - assigns, s and m, to a - b.
*/

static void SubTime (unsigned int *s, unsigned int *m, Selective_Timeval a, Selective_Timeval b)
{
  unsigned int as;
  unsigned int am;
  unsigned int bs;
  unsigned int bm;

  Selective_GetTime (a, &as, &am);
  Assertion_Assert (am < Microseconds);
  Selective_GetTime (b, &bs, &bm);
  Assertion_Assert (bm < Microseconds);
  if (IsGreaterEqual (a, b))
    {
      (*s) = as-bs;
      if (am >= bm)
        {
          (*m) = am-bm;
          Assertion_Assert ((*m) < Microseconds);
        }
      else
        {
          Assertion_Assert ((*s) > 0);
          (*s) -= 1;
          (*m) = (Microseconds+am)-bm;
          Assertion_Assert ((*m) < Microseconds);
        }
    }
  else
    {
      (*s) = 0;
      (*m) = 0;
    }
}


/*
   activatePending - activates the first interrupt pending and clears it.
*/

static bool activatePending (bool untilInterrupt, RTint_DispatchVector call, unsigned int pri, int maxFd, Selective_SetOfFd *inSet, Selective_SetOfFd *outSet, Selective_Timeval *timeval, Selective_Timeval b4, Selective_Timeval after)
{
  int result;
  unsigned int p;
  RTint_Vector vec;
  unsigned int b4s;
  unsigned int b4m;
  unsigned int afs;
  unsigned int afm;
  unsigned int sec;
  unsigned int micro;

  RTco_wait (lock);
  p = static_cast<unsigned int> (7);
  while (p > pri)
    {
      vec = Pending.array[p-(COROUTINES_UnassignedPriority)];
      while (vec != NULL)
        {
          switch (vec->type)
            {
              case RTint_input:
                if (((vec->File < maxFd) && ((*inSet) != NULL)) && (Selective_FdIsSet (vec->File, (*inSet))))
                  {
                    if (Debugging)
                      {
                        libc_printf ((const char *) "read (fd=%d) is ready (vec=%d)\\n", 32, vec->File, vec->no);
                        DumpPendingQueue ();
                      }
                    Selective_FdClr (vec->File, (*inSet));  /* so we dont activate this again from our select.  */
                    RTco_signal (lock);  /* so we dont activate this again from our select.  */
                    (*call.proc) (vec->no, vec->priority, vec->arg);
                    return true;
                  }
                break;

              case RTint_output:
                if (((vec->File < maxFd) && ((*outSet) != NULL)) && (Selective_FdIsSet (vec->File, (*outSet))))
                  {
                    if (Debugging)
                      {
                        libc_printf ((const char *) "write (fd=%d) is ready (vec=%d)\\n", 33, vec->File, vec->no);
                        DumpPendingQueue ();
                      }
                    Selective_FdClr (vec->File, (*outSet));  /* so we dont activate this again from our select.  */
                    RTco_signal (lock);  /* so we dont activate this again from our select.  */
                    (*call.proc) (vec->no, vec->priority, vec->arg);
                    return true;
                  }
                break;

              case RTint_time:
                if (untilInterrupt && ((*timeval) != NULL))
                  {
                    result = Selective_GetTimeOfDay (after);
                    Assertion_Assert (result == 0);
                    if (Debugging)
                      {
                        Selective_GetTime ((*timeval), &sec, &micro);
                        Assertion_Assert (micro < Microseconds);
                        Selective_GetTime (after, &afs, &afm);
                        Assertion_Assert (afm < Microseconds);
                        Selective_GetTime (b4, &b4s, &b4m);
                        Assertion_Assert (b4m < Microseconds);
                        libc_printf ((const char *) "waited %u.%06u + %u.%06u now is %u.%06u\\n", 41, sec, micro, b4s, b4m, afs, afm);
                      }
                    if (IsGreaterEqual (after, vec->abs_))
                      {
                        if (Debugging)
                          {
                            DumpPendingQueue ();
                            libc_printf ((const char *) "time has expired calling dispatcher\\n", 37);
                          }
                        (*timeval) = Selective_KillTime ((*timeval));  /* so we dont activate this again from our select.  */
                        RTco_signal (lock);  /* so we dont activate this again from our select.  */
                        if (Debugging)
                          {
                            libc_printf ((const char *) "call (%d, %d, 0x%x)\\n", 21, vec->no, vec->priority, vec->arg);
                          }
                        (*call.proc) (vec->no, vec->priority, vec->arg);
                        return true;
                      }
                    else if (Debugging)
                      {
                        /* avoid dangling else.  */
                        libc_printf ((const char *) "must wait longer as time has not expired\\n", 42);
                      }
                  }
                break;


              default:
                CaseException ("../../gcc/m2/gm2-libs/RTint.def", 25, 1);
                __builtin_unreachable ();
            }
          vec = vec->pending;
        }
      p -= 1;
    }
  RTco_signal (lock);
  return false;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   init -
*/

static void init (void)
{
  COROUTINES_PROTECTION p;

  lock = RTco_initSemaphore (1);
  RTco_wait (lock);
  Exists = NULL;
  for (p=COROUTINES_UnassignedPriority; p<=7; p++)
    {
      Pending.array[p-(COROUTINES_UnassignedPriority)] = NULL;
    }
  initialized = true;
  RTco_signal (lock);
}


/*
   InitInputVector - returns an interrupt vector which is associated
                     with the file descriptor, fd.
*/

extern "C" unsigned int RTint_InitInputVector (int fd, unsigned int pri)
{
  RTint_Vector vptr;

  if (Debugging)
    {
      libc_printf ((const char *) "InitInputVector fd = %d priority = %d\\n", 39, fd, pri);
    }
  RTco_wait (lock);
  vptr = FindVector (fd, RTint_input);
  if (vptr == NULL)
    {
      Storage_ALLOCATE ((void **) &vptr, sizeof (RTint__T1));
      VecNo += 1;
      vptr->type = RTint_input;
      vptr->priority = pri;
      vptr->arg = NULL;
      vptr->pending = NULL;
      vptr->exists = Exists;
      vptr->no = VecNo;
      vptr->File = fd;
      Exists = vptr;
      RTco_signal (lock);
      return VecNo;
    }
  else
    {
      RTco_signal (lock);
      return vptr->no;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   InitOutputVector - returns an interrupt vector which is associated
                      with the file descriptor, fd.
*/

extern "C" unsigned int RTint_InitOutputVector (int fd, unsigned int pri)
{
  RTint_Vector vptr;

  RTco_wait (lock);
  vptr = FindVector (fd, RTint_output);
  if (vptr == NULL)
    {
      Storage_ALLOCATE ((void **) &vptr, sizeof (RTint__T1));
      if (vptr == NULL)
        {
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
      else
        {
          VecNo += 1;
          vptr->type = RTint_output;
          vptr->priority = pri;
          vptr->arg = NULL;
          vptr->pending = NULL;
          vptr->exists = Exists;
          vptr->no = VecNo;
          vptr->File = fd;
          Exists = vptr;
          RTco_signal (lock);
          return VecNo;
        }
    }
  else
    {
      RTco_signal (lock);
      return vptr->no;
    }
  ReturnException ("../../gcc/m2/gm2-libs/RTint.def", 25, 1);
  __builtin_unreachable ();
}


/*
   InitTimeVector - returns an interrupt vector associated with
                    the relative time.
*/

extern "C" unsigned int RTint_InitTimeVector (unsigned int micro, unsigned int secs, unsigned int pri)
{
  RTint_Vector vptr;

  RTco_wait (lock);
  Storage_ALLOCATE ((void **) &vptr, sizeof (RTint__T1));
  if (vptr == NULL)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  else
    {
      VecNo += 1;
      Assertion_Assert (micro < Microseconds);
      vptr->type = RTint_time;
      vptr->priority = pri;
      vptr->arg = NULL;
      vptr->pending = NULL;
      vptr->exists = Exists;
      vptr->no = VecNo;
      vptr->rel = Selective_InitTime (secs+DebugTime, micro);
      vptr->abs_ = Selective_InitTime (0, 0);
      vptr->queued = false;
      Exists = vptr;
    }
  RTco_signal (lock);
  return VecNo;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ReArmTimeVector - reprimes the vector, vec, to deliver an interrupt
                     at the new relative time.
*/

extern "C" void RTint_ReArmTimeVector (unsigned int vec, unsigned int micro, unsigned int secs)
{
  RTint_Vector vptr;

  Assertion_Assert (micro < Microseconds);
  RTco_wait (lock);
  vptr = FindVectorNo (vec);
  if (vptr == NULL)
    {
      M2RTS_Halt ((const char *) "cannot find vector supplied", 27, (const char *) "../../gcc/m2/gm2-libs/RTint.mod", 31, (const char *) "ReArmTimeVector", 15, 287);
    }
  else
    {
      Selective_SetTime (vptr->rel, secs+DebugTime, micro);
    }
  RTco_signal (lock);
}


/*
   GetTimeVector - assigns, micro, and, secs, with the remaining
                   time before this interrupt will expire.
                   This value is only updated when a Listen
                   occurs.
*/

extern "C" void RTint_GetTimeVector (unsigned int vec, unsigned int *micro, unsigned int *secs)
{
  RTint_Vector vptr;

  RTco_wait (lock);
  vptr = FindVectorNo (vec);
  if (vptr == NULL)
    {
      M2RTS_Halt ((const char *) "cannot find vector supplied", 27, (const char *) "../../gcc/m2/gm2-libs/RTint.mod", 31, (const char *) "GetTimeVector", 13, 313);
    }
  else
    {
      Selective_GetTime (vptr->rel, secs, micro);
      Assertion_Assert ((*micro) < Microseconds);
    }
  RTco_signal (lock);
}


/*
   AttachVector - adds the pointer ptr to be associated with the interrupt
                  vector. It returns the previous value attached to this
                  vector.
*/

extern "C" void * RTint_AttachVector (unsigned int vec, void * ptr)
{
  RTint_Vector vptr;
  void * prevArg;

  RTco_wait (lock);
  vptr = FindVectorNo (vec);
  if (vptr == NULL)
    {
      M2RTS_Halt ((const char *) "cannot find vector supplied", 27, (const char *) "../../gcc/m2/gm2-libs/RTint.mod", 31, (const char *) "AttachVector", 12, 340);
    }
  else
    {
      prevArg = vptr->arg;
      vptr->arg = ptr;
      if (Debugging)
        {
          libc_printf ((const char *) "AttachVector %d with %p\\n", 25, vec, ptr);
          DumpPendingQueue ();
        }
      RTco_signal (lock);
      return prevArg;
    }
  ReturnException ("../../gcc/m2/gm2-libs/RTint.def", 25, 1);
  __builtin_unreachable ();
}


/*
   IncludeVector - includes, vec, into the dispatcher list of
                   possible interrupt causes.
*/

extern "C" void RTint_IncludeVector (unsigned int vec)
{
  RTint_Vector vptr;
  unsigned int micro;
  unsigned int sec;
  int result;

  RTco_wait (lock);
  vptr = FindPendingVector (vec);
  if (vptr == NULL)
    {
      /* avoid dangling else.  */
      vptr = FindVectorNo (vec);
      if (vptr == NULL)
        {
          M2RTS_Halt ((const char *) "cannot find vector supplied", 27, (const char *) "../../gcc/m2/gm2-libs/RTint.mod", 31, (const char *) "IncludeVector", 13, 374);
        }
      else
        {
          /* printf('including vector %d  (fd = %d)
          ', vec, v^.File) ;  */
          vptr->pending = Pending.array[vptr->priority-(COROUTINES_UnassignedPriority)];
          Pending.array[vptr->priority-(COROUTINES_UnassignedPriority)] = vptr;
          if ((vptr->type == RTint_time) && ! vptr->queued)
            {
              vptr->queued = true;
              result = Selective_GetTimeOfDay (vptr->abs_);
              Assertion_Assert (result == 0);
              Selective_GetTime (vptr->abs_, &sec, &micro);
              Assertion_Assert (micro < Microseconds);
              AddTime (vptr->abs_, vptr->rel);
              Selective_GetTime (vptr->abs_, &sec, &micro);
              Assertion_Assert (micro < Microseconds);
            }
        }
    }
  else
    {
      if (Debugging)
        {
          libc_printf ((const char *) "odd vector (%d) type (%d) arg (%p) is already attached to the pending queue\\n", 77, vec, vptr->type, vptr->arg);
        }
    }
  RTco_signal (lock);
}


/*
   ExcludeVector - excludes, vec, from the dispatcher list of
                   possible interrupt causes.
*/

extern "C" void RTint_ExcludeVector (unsigned int vec)
{
  RTint_Vector vptr;
  RTint_Vector uptr;

  RTco_wait (lock);
  vptr = FindPendingVector (vec);
  if (vptr == NULL)
    {
      M2RTS_Halt ((const char *) "cannot find pending vector supplied", 35, (const char *) "../../gcc/m2/gm2-libs/RTint.mod", 31, (const char *) "ExcludeVector", 13, 416);
    }
  else
    {
      /* printf('excluding vector %d
      ', vec) ;  */
      if (Pending.array[vptr->priority-(COROUTINES_UnassignedPriority)] == vptr)
        {
          Pending.array[vptr->priority-(COROUTINES_UnassignedPriority)] = Pending.array[vptr->priority-(COROUTINES_UnassignedPriority)]->pending;
        }
      else
        {
          uptr = Pending.array[vptr->priority-(COROUTINES_UnassignedPriority)];
          while (uptr->pending != vptr)
            {
              uptr = uptr->pending;
            }
          uptr->pending = vptr->pending;
        }
      if (vptr->type == RTint_time)
        {
          vptr->queued = false;
        }
    }
  RTco_signal (lock);
}


/*
   Listen - will either block indefinitely (until an interrupt)
            or alteratively will test to see whether any interrupts
            are pending.
            If a pending interrupt was found then, call, is called
            and then this procedure returns.
            It only listens for interrupts > pri.
*/

extern "C" void RTint_Listen (bool untilInterrupt, RTint_DispatchVector call, unsigned int pri)
{
  bool found;
  int result;
  Selective_Timeval zero;
  Selective_Timeval after;
  Selective_Timeval b4;
  Selective_Timeval timeval;
  RTint_Vector vec;
  Selective_SetOfFd inSet;
  Selective_SetOfFd outSet;
  unsigned int sec;
  unsigned int micro;
  int maxFd;
  unsigned int p;

  RTco_wait (lock);
  if (pri < (7))
    {
      if (Debugging)
        {
          DumpPendingQueue ();
        }
      maxFd = -1;
      timeval = NULL;
      inSet = NULL;
      outSet = NULL;
      timeval = Selective_InitTime (static_cast<unsigned int> (INT_MAX), 0);
      p = static_cast<unsigned int> (7);
      found = false;
      while (p > pri)
        {
          vec = Pending.array[p-(COROUTINES_UnassignedPriority)];
          while (vec != NULL)
            {
              switch (vec->type)
                {
                  case RTint_input:
                    AddFd (&inSet, &maxFd, vec->File);
                    break;

                  case RTint_output:
                    AddFd (&outSet, &maxFd, vec->File);
                    break;

                  case RTint_time:
                    if (IsGreaterEqual (timeval, vec->abs_))
                      {
                        Selective_GetTime (vec->abs_, &sec, &micro);
                        Assertion_Assert (micro < Microseconds);
                        if (Debugging)
                          {
                            libc_printf ((const char *) "shortest delay is %u.%06u\\n", 27, sec, micro);
                          }
                        Selective_SetTime (timeval, sec, micro);
                        found = true;
                      }
                    break;


                  default:
                    CaseException ("../../gcc/m2/gm2-libs/RTint.def", 25, 1);
                    __builtin_unreachable ();
                }
              vec = vec->pending;
            }
          p -= 1;
        }
      if (! untilInterrupt)
        {
          Selective_SetTime (timeval, 0, 0);
        }
      if ((untilInterrupt && (((inSet == NULL) && (outSet == NULL)) || (maxFd == -1))) && ! found)
        {
          M2RTS_Halt ((const char *) "deadlock found, no more processes to run and no interrupts active", 65, (const char *) "../../gcc/m2/gm2-libs/RTint.mod", 31, (const char *) "Listen", 6, 733);
        }
      /* printf('}
      ') ;  */
      if (! found && (maxFd == -1))
        {
          /* no file descriptors to be selected upon.  */
          timeval = Selective_KillTime (timeval);
          RTco_signal (lock);
          return;
        }
      else
        {
          Selective_GetTime (timeval, &sec, &micro);
          Assertion_Assert (micro < Microseconds);
          zero = Selective_InitTime (0, 0);
          b4 = Selective_InitTime (0, 0);
          after = Selective_InitTime (0, 0);
          result = Selective_GetTimeOfDay (b4);
          Assertion_Assert (result == 0);
          SubTime (&sec, &micro, timeval, b4);
          Selective_SetTime (timeval, sec, micro);
          if (Debugging)
            {
              libc_printf ((const char *) "select waiting for %u.%06u seconds\\n", 36, sec, micro);
            }
          RTco_signal (lock);
          do {
            if (Debugging)
              {
                libc_printf ((const char *) "select (.., .., .., %u.%06u)\\n", 30, sec, micro);
              }
            if (maxFd < 0)
              {
                result = RTco_select (0, NULL, NULL, NULL, timeval);
              }
            else
              {
                result = RTco_select (maxFd+1, inSet, outSet, NULL, timeval);
              }
            if (result == -1)
              {
                if (Debugging)
                  {
                    libc_perror ((const char *) "select failed : ", 16);
                  }
                result = RTco_select (maxFd+1, inSet, outSet, NULL, zero);
                if (result != -1)
                  {
                    Selective_GetTime (timeval, &sec, &micro);
                    if (Debugging)
                      {
                        libc_printf ((const char *) "(nfds : %d timeval: %u.%06u) : \\n", 33, maxFd, sec, micro);
                      }
                    libc_perror ((const char *) "select timeout argument was faulty : ", 37);
                  }
                else
                  {
                    result = RTco_select (maxFd+1, inSet, NULL, NULL, timeval);
                    if (result != -1)
                      {
                        libc_perror ((const char *) "select output fd argument was faulty : ", 39);
                      }
                    else
                      {
                        result = RTco_select (maxFd+1, NULL, outSet, NULL, timeval);
                        if (result != -1)
                          {
                            libc_perror ((const char *) "select input fd argument was faulty : ", 38);
                          }
                        else
                          {
                            if (maxFd == -1)
                              {
                                /* avoid dangling else.  */
                                result = RTco_select (0, NULL, NULL, NULL, timeval);
                                if (result == -1)
                                  {
                                    if (Debugging)
                                      {
                                        libc_perror ((const char *) "select does not accept nfds == 0 ", 33);
                                      }
                                    result = 0;
                                  }
                              }
                            else
                              {
                                libc_perror ((const char *) "select maxFD+1 argument was faulty : ", 37);
                              }
                          }
                      }
                  }
              }
          } while (! (result != -1));
        }
      while (activatePending (untilInterrupt, call, pri, maxFd+1, &inSet, &outSet, &timeval, b4, after))
        {}  /* empty.  */
      if (timeval != NULL)
        {
          timeval = Selective_KillTime (timeval);
        }
      if (zero != NULL)
        {
          zero = Selective_KillTime (zero);
        }
      if (after != NULL)
        {
          after = Selective_KillTime (after);
        }
      if (b4 != NULL)
        {
          b4 = Selective_KillTime (b4);
        }
      if (inSet != NULL)
        {
          inSet = Selective_KillSet (inSet);
        }
      if (outSet != NULL)
        {
          outSet = Selective_KillSet (outSet);
        }
    }
  RTco_signal (lock);
}


/*
   Init -
*/

extern "C" void RTint_Init (void)
{
  if (! initialized)
    {
      init ();
    }
}

extern "C" void _M2_RTint_init (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
{
  RTint_Init ();
}

extern "C" void _M2_RTint_fini (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
{
}