<commit_before>#include <tcl.h>
#include <signal.h>
#include "sigobj.h"
#include "syncpoints.h"
#include "events.h"
#include "utils.h"
#include "sigmanip.h"
#include "trap.h"



/* POSIX.1-2001 signal handler */
static
void
SignalAction (
    int signum,
    siginfo_t *si,
    void *uctx
    )
{
    LockSyncPoints();
    SignalSyncPoint(signum);
    UnlockSyncPoints();
}


static
int
InstallSignalHandler (
    int signum
    )
{
    struct sigaction sa;

    sa.sa_flags     = SA_RESTART | SA_SIGINFO;
    sa.sa_sigaction = &SignalAction;
    sigfillset(&sa.sa_mask);

    return sigaction(signum, &sa, NULL);
}


static
int
TrapSet (
    ClientData clientData,
    Tcl_Interp *interp,
    Tcl_Obj *sigObj,
    Tcl_Obj *newCmdObj
    )
{
    int id, res;

    id = GetSignumFromObj(interp, sigObj);
    if (id == -1) {
	return TCL_ERROR;
    }

    /* TODO SetEventHandler() should return some
     * flag telling us whether the new script was
     * installed/modified or deleted. In the latter
     * case we should delete the syncpoint and
     * change signal disposition to SIG_DFL.
     * Note that this looks like a ternary logic:
     * o Script is set
     * o Script is deleted
     * o No change
     */
    SetEventHandler(id, interp, newCmdObj);

    BlockAllSignals();
    LockSyncPoints();
    SetSyncPoint(id);
    UnlockSyncPoints();
    UnblockAllSignals();

    Tcl_SetErrno(0);
    res = InstallSignalHandler(id);
    if (res != 0) {
	/* FIXME ideally we should somehow revert changes
	 * made to cmdObj */
	ReportPosixError(interp);
	return TCL_ERROR;
    }

    return TCL_OK;
}


static
int
TrapGet (
    ClientData clientData,
    Tcl_Interp *interp,
    Tcl_Obj *sigObj
    )
{
    int id;
    Tcl_Obj *cmdObj;

    id = GetSignumFromObj(interp, sigObj);
    if (id == -1) {
	return TCL_ERROR;
    }

    cmdObj = GetEventHandlerCommand(id);
    if (cmdObj != NULL) {
	Tcl_SetObjResult(interp, cmdObj);
    } else {
	/* Do nothing in this case, as it is guaranteed
	 * that the interp result was reset to an empty
	 * string befor calling our command */
    }
    return TCL_OK;
}


MODULE_SCOPE
int
Command_Trap (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    switch (objc) {
	case 3:
	    return TrapGet(clientData, interp, objv[2]);
	case 4:
	    return TrapSet(clientData, interp, objv[2], objv[3]);
	default:
	    Tcl_WrongNumArgs(interp, 2, objv, "signal ?command?");
	    return TCL_ERROR;
    }
}

/* vim: set ts=8 sts=4 sw=4 sts=4 noet: */<commit_msg>Add sketch of the new trap management code<commit_after>#include <tcl.h>
#include <signal.h>
#include "sigobj.h"
#include "syncpoints.h"
#include "events.h"
#include "utils.h"
#include "sigmanip.h"
#include "trap.h"



static void LockWorld (void);
static void UnlockWorld (void);



/* POSIX.1-2001 signal handler */
static
void
SignalAction (
    int signum,
    siginfo_t *si,
    void *uctx
    )
{
    LockSyncPoints();
    SignalSyncPoint(signum);
    UnlockSyncPoints();
}


static
int
InstallSignalHandler (
    int signum
    )
{
    struct sigaction sa;

    sa.sa_flags     = SA_RESTART | SA_SIGINFO;
    sa.sa_sigaction = &SignalAction;
    sigfillset(&sa.sa_mask);

    return sigaction(signum, &sa, NULL);
}


static
int
TrapSet (
    ClientData clientData,
    Tcl_Interp *interp,
    Tcl_Obj *sigObj,
    Tcl_Obj *newCmdObj
    )
{
    int id, res, isnew;

    id = GetSignumFromObj(interp, sigObj);
    if (id == -1) {
	return TCL_ERROR;
    }

    if (IsEmptyString(newCmdObj)) {
	/* Deletion of trap is requested */
	SyncPoint *spointPtr;

	LockWorld();
	spointPtr = GetSyncPoint(id);
	if (spointPtr == NULL) {
	    /* Do nothing -- syncpoint does not exist */
	    UnlockWorld();
	    return TCL_OK;
	} else {
	    DeleteSyncPoint(spointPtr);
	    UninstallEventHandler(id);
	    UnlockWorld();
	    DeleteEventHandler(id);
	    return TCL_OK;
	}
    } else {
	/* Trapping of the signal is requested */
	SyncPoint *spointPtr;
	int isnew;

	LockWorld();
	isnew = SetSyncPoint(id);
	if (isnew) {
	    Tcl_SetErrno(0);
	    res = InstallSignalHandler(id);
	    if (res != 0) {
		/* TODO delete syncpoint created above.
		 * Note that this poses another interesting problem:
		 * how to handle deletion of a syncpoint if it has
		 * pending signals on it? */
		ReportPosixError(interp);
		UnlockWorld();
		return TCL_ERROR;
	    }
	}
	SetEventHandler(id, interp, newCmdObj);
	UnlockWorld();
	return TCL_OK;
    }
}


static
int
TrapGet (
    ClientData clientData,
    Tcl_Interp *interp,
    Tcl_Obj *sigObj
    )
{
    int id;
    Tcl_Obj *cmdObj;

    id = GetSignumFromObj(interp, sigObj);
    if (id == -1) {
	return TCL_ERROR;
    }

    cmdObj = GetEventHandlerCommand(id);
    if (cmdObj != NULL) {
	Tcl_SetObjResult(interp, cmdObj);
    } else {
	/* Do nothing in this case, as it is guaranteed
	 * that the interp result was reset to an empty
	 * string befor calling our command */
    }
    return TCL_OK;
}


MODULE_SCOPE
int
Command_Trap (
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[]
    )
{
    switch (objc) {
	case 3:
	    return TrapGet(clientData, interp, objv[2]);
	case 4:
	    return TrapSet(clientData, interp, objv[2], objv[3]);
	default:
	    Tcl_WrongNumArgs(interp, 2, objv, "signal ?command?");
	    return TCL_ERROR;
    }
}



static void
LockWorld (void)
{
    BlockAllSignals();
    LockSyncPoints();
}

static void
UnlockWorld(void)
{
    UnlockSyncPoints();
    UnblockAllSignals();
}

/* vim: set ts=8 sts=4 sw=4 sts=4 noet: */
{'fraction_non_alphanumeric': 0.1111111111111111, 'fraction_numerical': 0.006821037515706336, 'mean_word_length': 2.9184247538677917, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3040124', 'n_tokens_mistral': 2104, 'n_tokens_neox': 2008, 'n_words': 529}