/*
 * signal.c
 *
 * Description:
 * Thread-aware signal functions.
 *
 * --------------------------------------------------------------------------
 *
 *      Pthreads-win32 - POSIX Threads Library for Win32
 *      Copyright(C) 1998 John E. Bossom
 *      Copyright(C) 1999,2005 Pthreads-win32 contributors
 * 
 *      Contact Email: rpj@callisto.canberra.edu.au
 * 
 *      The current list of contributors is contained
 *      in the file CONTRIBUTORS included with the source
 *      code distribution. The list can also be seen at the
 *      following World Wide Web location:
 *      http://sources.redhat.com/pthreads-win32/contributors.html
 * 
 *      This library is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU Lesser 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
 *      Lesser General Public License for more details.
 * 
 *      You should have received a copy of the GNU Lesser General Public
 *      License along with this library in the file COPYING.LIB;
 *      if not, write to the Free Software Foundation, Inc.,
 *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

/*
 * Possible future strategy for implementing pthread_kill()
 * ========================================================
 *
 * Win32 does not implement signals.
 * Signals are simply software interrupts.
 * pthread_kill() asks the system to deliver a specified
 * signal (interrupt) to a specified thread in the same
 * process.
 * Signals are always asynchronous (no deferred signals).
 * Pthread-win32 has an async cancelation mechanism.
 * A similar system can be written to deliver signals
 * within the same process (on ix86 processors at least).
 *
 * Each thread maintains information about which
 * signals it will respond to. Handler routines
 * are set on a per-process basis - not per-thread.
 * When signalled, a thread will check it's sigmask
 * and, if the signal is not being ignored, call the
 * handler routine associated with the signal. The
 * thread must then (except for some signals) return to
 * the point where it was interrupted.
 *
 * Ideally the system itself would check the target thread's
 * mask before possibly needlessly bothering the thread
 * itself. This could be done by pthread_kill(), that is,
 * in the signaling thread since it has access to
 * all pthread_t structures. It could also retrieve
 * the handler routine address to minimise the target
 * threads response overhead. This may also simplify
 * serialisation of the access to the per-thread signal
 * structures.
 *
 * pthread_kill() eventually calls a routine similar to
 * ptw32_cancel_thread() which manipulates the target
 * threads processor context to cause the thread to
 * run the handler launcher routine. pthread_kill() must
 * save the target threads current context so that the
 * handler launcher routine can restore the context after
 * the signal handler has returned. Some handlers will not
 * return, eg. the default SIGKILL handler may simply
 * call pthread_exit().
 *
 * The current context is saved in the target threads
 * pthread_t structure.
 */

#include "pthread.h"
#include "implement.h"

#if defined(HAVE_SIGSET_T)

static void
ptw32_signal_thread ()
{
}

static void
ptw32_signal_callhandler ()
{
}

int
pthread_sigmask (int how, sigset_t const *set, sigset_t * oset)
{
  pthread_t thread = pthread_self ();

  if (thread.p == NULL)
    {
      return ENOENT;
    }

  /* Validate the `how' argument. */
  if (set != NULL)
    {
      switch (how)
	{
	case SIG_BLOCK:
	  break;
	case SIG_UNBLOCK:
	  break;
	case SIG_SETMASK:
	  break;
	default:
	  /* Invalid `how' argument. */
	  return EINVAL;
	}
    }

  /* Copy the old mask before modifying it. */
  if (oset != NULL)
    {
      memcpy (oset, &(thread.p->sigmask), sizeof (sigset_t));
    }

  if (set != NULL)
    {
      unsigned int i;

      /* FIXME: this code assumes that sigmask is an even multiple of
         the size of a long integer. */

      unsigned long *src = (unsigned long const *) set;
      unsigned long *dest = (unsigned long *) &(thread.p->sigmask);

      switch (how)
	{
	case SIG_BLOCK:
	  for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++)
	    {
	      /* OR the bit field longword-wise. */
	      *dest++ |= *src++;
	    }
	  break;
	case SIG_UNBLOCK:
	  for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++)
	    {
	      /* XOR the bitfield longword-wise. */
	      *dest++ ^= *src++;
	    }
	case SIG_SETMASK:
	  /* Replace the whole sigmask. */
	  memcpy (&(thread.p->sigmask), set, sizeof (sigset_t));
	  break;
	}
    }

  return 0;
}

int
sigwait (const sigset_t * set, int *sig)
{
  /* This routine is a cancellation point */
  pthread_test_cancel();
}

int
sigaction (int signum, const struct sigaction *act, struct sigaction *oldact)
{
}

#endif /* HAVE_SIGSET_T */
