/*
    $Id$
    $Log$
    Desc:
    Lang: english
*/
#include "exec_intern.h"

/*****************************************************************************

    NAME */
	#include <clib/exec_protos.h>

	__AROS_LH1(BYTE, AllocSignal,

/*  SYNOPSIS */
	__AROS_LA(long, signalNum, D0),

/*  LOCATION */
	struct ExecBase *, SysBase, 55, Exec)

/*  FUNCTION
	Allocate a given signal out of the current task's pool of signals.
	Every task has a set of signals to communicate with other tasks.
	Half of them are reserved for the system and half of them is
	free for general use. Some of the reserved signals (e.g.
	SIGBREAKF_CTRL_C) have a defined behaviour and may be used by user
	code, however.

    INPUTS
	signalNum - Number of the signal to allocate or -1 if any signal
		    will do.

    RESULT
	Number of the signal or -1 if the signal couldn't be allocated.

    NOTES

    EXAMPLE

    BUGS

    SEE ALSO
	FreeSignal(), Signal(), Wait()

    INTERNALS

    HISTORY
	29-10-95    digulla automatically created from
			    exec_lib.fd and clib/exec_protos.h
	17-12-95    digulla Incorporated code by Matthias Fleischner

*****************************************************************************/
{
    __AROS_FUNC_INIT
    ULONG *mask;
    ULONG mask1;

    /* Protect signal mask against possible task exceptions. */
    Forbid();

    /* Get pointer to mask of allocated signal */
    mask=&SysBase->ThisTask->tc_SigAlloc;

    /* Get signal */
    if(signalNum<0)
    {
	/* Any signal will do. */

	/*
	 * To get the last nonzero bit in a number I use a&~a+1:
	 * Given a number that ends with a row of zeros  xxxx1000
	 * I first toggle all bits in that number	 XXXX0111
	 * then add 1 to toggle all but the last 0 again XXXX1000
	 * and AND this with the original number	 00001000
	 *
	 * And since ~a+1=-a I can use a&-a instead.
	 *
	 * And to get the last zero bit I finally use ~a&-~a.
	 */
	mask1=~*mask&-~*mask;

	/* Got a bit? */
	if(mask1)
	{
	    /* Allocate and reset the bit */
	    *mask|=mask1;
	    SysBase->ThisTask->tc_SigRecvd&=~mask1;

	    /* And get the bit number */
	    signalNum=(mask1&0xffff0000?16:0)+(mask1&0xff00ff00?8:0)+
		      (mask1&0xf0f0f0f0? 4:0)+(mask1&0xcccccccc?2:0)+
		      (mask1&0xaaaaaaaa? 1:0);
	}
    }else
    {
	/* Get a specific signal */
	mask1=1<<signalNum;

	/* Check if signal is free */
	if(*mask&mask1)
	    /* No. Return */
	    signalNum=-1;
	else
	{
	    /* It is free. Allocate and reset it. */
	    *mask|=mask1;
	    SysBase->ThisTask->tc_SigRecvd&=~mask1;
	}
    }

    Permit();

    return (BYTE)signalNum;
    __AROS_FUNC_EXIT
} /* AllocSignal */
