4 * Tcl Unix signal support routines and the signal and commands.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
14 *-----------------------------------------------------------------------------
15 * $Id: tclXsignal.c,v 2.0 1992/10/16 04:51:12 markd Rel $
16 *-----------------------------------------------------------------------------
23 # define SIGCLD SIGCHLD
26 # define SIGCHLD SIGCLD
34 * Signal name table maps name to number.
37 #define SIG_NAME_MAX 7
39 static struct {char *name
;
91 #ifdef TCL_SIG_PROC_INT
92 # define SIG_PROC_RET_TYPE int
94 # define SIG_PROC_RET_TYPE void
97 typedef SIG_PROC_RET_TYPE (*signalProcPtr_t
) _ANSI_ARGS_((int));
100 * Class of actions that can be set by the signal command.
102 #define SIGACT_SET 1 /* Set the signal */
103 #define SIGACT_GET 2 /* Get the signal */
104 #define SIGACT_BLOCK 3 /* Block the signal */
105 #define SIGACT_UNBLOCK 4 /* Unblock the signal */
108 * Defines if this is not Posix.
112 # define SIG_UNBLOCK 2
118 static char *noPosix
= "Posix signals are not available on this system";
121 * Globals that indicate that some signal was received and how many of each
122 * signal type has not yet been processed.
124 int tclReceivedSignal
= FALSE
; /* A signal was received */
125 static unsigned signalsReceived
[MAXSIG
]; /* Counters of signals */
128 * Table of commands to evaluate when a signal occurs. If the command is
129 * NULL and the signal is received, an error is returned.
131 static char *signalTrapCmds
[MAXSIG
];
134 * Prototypes of internal functions.
138 SigNameToNum
_ANSI_ARGS_((char *sigName
));
140 static signalProcPtr_t
141 GetSignalState
_ANSI_ARGS_((int signalNum
));
144 SetSignalAction
_ANSI_ARGS_((int signalNum
,
145 signalProcPtr_t sigFunc
));
147 static SIG_PROC_RET_TYPE
148 TclSignalTrap
_ANSI_ARGS_((int signalNum
));
151 EvalTrapCode
_ANSI_ARGS_((Tcl_Interp
*interp
,
156 ParseSignalList
_ANSI_ARGS_((Tcl_Interp
*interp
,
161 SignalBlocked
_ANSI_ARGS_((Tcl_Interp
*interp
,
165 GetSignalStates
_ANSI_ARGS_((Tcl_Interp
*interp
,
167 int signalList
[MAXSIG
]));
170 SetSignalStates
_ANSI_ARGS_((Tcl_Interp
*interp
,
172 int signalList
[MAXSIG
],
173 signalProcPtr_t actionFunc
,
177 BlockSignals
_ANSI_ARGS_((Tcl_Interp
*interp
,
180 int signalList
[MAXSIG
]));
183 SignalCmdCleanUp
_ANSI_ARGS_((ClientData clientData
));
187 *-----------------------------------------------------------------------------
190 * Converts a UNIX signal name to its number, returns -1 if not found.
191 * the name may be upper or lower case and may optionally have the
192 * leading "SIG" omitted.
194 *-----------------------------------------------------------------------------
197 SigNameToNum (sigName
)
200 char sigNameUp
[SIG_NAME_MAX
+1]; /* Upshifted signal name */
205 * Copy and upshift requested name.
208 if (strlen (sigName
) > SIG_NAME_MAX
)
209 return -1; /* Name too long */
211 Tcl_UpShift (sigNameUp
, sigName
);
213 if (STRNEQU (sigNameUp
, "SIG", 3))
214 sigNamePtr
= &sigNameUp
[3];
216 sigNamePtr
= sigNameUp
;
218 for (idx
= 0; sigNameTable
[idx
].num
!= -1; idx
++)
219 if (STREQU (sigNamePtr
, sigNameTable
[idx
].name
))
222 return sigNameTable
[idx
].num
;
226 *-----------------------------------------------------------------------------
229 * Implements the TCL kill command:
230 * kill [signal] proclist
233 * Standard TCL results, may return the UNIX system error message.
235 *-----------------------------------------------------------------------------
238 Tcl_KillCmd (clientData
, interp
, argc
, argv
)
239 ClientData clientData
;
244 int signalNum
, idx
, procId
, procArgc
, result
= TCL_ERROR
;
247 if ((argc
< 2) || (argc
> 3)) {
248 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
249 " [signal] processlist", (char *) NULL
);
256 if (!Tcl_StrToInt (argv
[1], 0, &signalNum
)) {
257 signalNum
= SigNameToNum (argv
[1]);
259 if ((signalNum
< 0) || (signalNum
> NSIG
)) {
260 Tcl_AppendResult (interp
, "invalid signal", (char *) NULL
);
265 if (Tcl_SplitList (interp
, argv
[argc
- 1], &procArgc
,
266 &procArgv
) != TCL_OK
)
269 for (idx
= 0; idx
< procArgc
; idx
++) {
271 if (Tcl_GetInt (interp
, procArgv
[idx
], &procId
) != TCL_OK
)
274 if (kill ((pid_t
) procId
, signalNum
) < 0) {
275 Tcl_AppendResult (interp
, "pid ", procArgv
[idx
],
276 ": ", Tcl_UnixError (interp
), (char *) NULL
);
283 ckfree ((char *) procArgv
);
288 *-----------------------------------------------------------------------------
291 * Get the current state of the specified signal.
293 * o signalNum (I) - Signal number to query.
295 * The signal function or SIG_DFL or SIG_IGN. If an error occures,
296 * SIG_ERR is returned (check errno);
297 *-----------------------------------------------------------------------------
299 static signalProcPtr_t
300 GetSignalState (signalNum
)
304 struct sigaction currentState
;
306 if (sigaction (signalNum
, NULL
, ¤tState
) < 0)
308 return currentState
.sa_handler
;
310 signalProcPtr_t actionFunc
;
312 if (signalNum
== SIGKILL
)
315 actionFunc
= signal (signalNum
, SIG_DFL
);
316 if (actionFunc
== SIG_ERR
)
318 if (actionFunc
!= SIG_DFL
)
319 signal (signalNum
, actionFunc
); /* reset */
325 *-----------------------------------------------------------------------------
328 * Set the action to occur when a signal is received.
330 * o signalNum (I) - Signal number to query.
331 * o sigFunc (O) - The signal function or SIG_DFL or SIG_IGN.
333 * TRUE if ok, FALSE if an error (check errno).
334 *-----------------------------------------------------------------------------
337 SetSignalAction (signalNum
, sigFunc
)
339 signalProcPtr_t sigFunc
;
342 struct sigaction newState
;
344 newState
.sa_handler
= sigFunc
;
345 sigfillset (&newState
.sa_mask
);
346 newState
.sa_flags
= 0;
348 if (sigaction (signalNum
, &newState
, NULL
) < 0)
353 if (signal (signalNum
, sigFunc
) == SIG_ERR
)
361 *-----------------------------------------------------------------------------
364 * Trap handler for UNIX signals. Sets a flag indicating that the
365 * trap has occured, saves the name and rearms the trap. The flag
366 * will be seen by the interpreter when its safe to trap.
368 * o tclReceivedSignal (O) - Set to TRUE, to indicate a signal was received.
369 * o signalsReceived (O) - The count of each signal that was received.
370 *-----------------------------------------------------------------------------
372 static SIG_PROC_RET_TYPE
373 TclSignalTrap (signalNum
)
377 * Set flags that are checked by the eval loop.
379 signalsReceived
[signalNum
]++;
380 tclReceivedSignal
= TRUE
;
382 #ifndef TCL_POSIX_SIG
384 * For old-style Unix signals, the signal must be explictly re-enabled.
385 * Not done for SIGCHLD, as we would continue to the signal until the
386 * wait is done. This is fixed by Posix signals and is not necessary under
387 * BSD, but it done this way for consistency.
389 if (signalNum
!= SIGCHLD
) {
390 if (SetSignalAction (signalNum
, TclSignalTrap
) < 0)
391 panic ("TclSignalTrap bug");
397 *-----------------------------------------------------------------------------
400 * Run code as the result of a signal. The code will be run in the
401 * global context, with the symbolic signal name in a global variable.
402 * signalReceived. If an error occured, then the result will be
403 * left in the interp, if no error occured, the result will be reset.
405 * o interp (I/O) - The interpreter to run the signal in.
406 * o signalNum (I) - The signal number of the signal that occured.
407 * o command (I) - The command string to execute.
409 * TCL_OK or TCL_ERROR.
410 *-----------------------------------------------------------------------------
413 EvalTrapCode (interp
, signalNum
, command
)
418 Interp
*iPtr
= (Interp
*) interp
;
421 CallFrame
*savedVarFramePtr
;
423 Tcl_ResetResult (interp
);
426 * Modify the interpreter state to execute in the global frame.
428 savedVarFramePtr
= iPtr
->varFramePtr
;
429 iPtr
->varFramePtr
= NULL
;
432 * Force name to always be SIGCHLD, even if system defines only SIGCLD.
434 if (signalNum
== SIGCHLD
)
435 signalName
= "SIGCHLD";
437 signalName
= Tcl_SignalId (signalNum
);
439 if (Tcl_SetVar (interp
, "signalReceived", signalName
,
440 TCL_GLOBAL_ONLY
| TCL_LEAVE_ERR_MSG
) == NULL
)
444 if (result
== TCL_OK
);
445 result
= Tcl_Eval (interp
, signalTrapCmds
[signalNum
], 0, NULL
);
448 * Restore the frame pointer and return the result (only OK or ERROR).
450 iPtr
->varFramePtr
= savedVarFramePtr
;
452 if (result
== TCL_ERROR
) {
453 char errorInfo
[TCL_RESULT_SIZE
];
455 sprintf (errorInfo
, "\n while executing signal trap code for %s%s",
456 signalName
, " signal");
457 Tcl_AddErrorInfo (interp
, errorInfo
);
461 Tcl_ResetResult (interp
);
467 *-----------------------------------------------------------------------------
469 * Tcl_ResetSignals --
471 * Reset all of the signal flags to indicate that no signals have
472 * occured. This is used by the shell at the beginning of each interactive
476 * o tclReceivedSignal (O) - Will be cleared.
477 * o signalsReceived (O) - The count of each signal that was received.
478 *-----------------------------------------------------------------------------
485 tclReceivedSignal
= 0;
486 for (signalNum
= 0; signalNum
< MAXSIG
; signalNum
++)
487 signalsReceived
[signalNum
] = 0;
492 *-----------------------------------------------------------------------------
494 * Tcl_CheckForSignal --
496 * Called by Tcl_Eval to check if a signal was received when Tcl_Eval is in
497 * a safe state. If the signal was received, this handles processing the
498 * signal prehaps recursively eval-ing some code. This is called just after a
499 * command completes. The results of the command are passed to this procedure
500 * and may be altered by it. If trap code is specified for the signal that
501 * was received, then the trap will be executed, otherwise an error result
502 * will be returned indicating that the signal occured. If an error is
503 * returned, clear the errorInfo variable. This makes sure it exists and
504 * that it is empty, otherwise bogus or non-existant information will be
505 * returned if this routine was called somewhere besides Tcl_Eval. If a
506 * signal was received multiple times and a trap is set on it, then that
507 * trap will be executed for each time the signal was received.
510 * o interp (I/O) - interp->result should contain the result for
511 * the command that just executed. This will either be restored or
512 * replaced with a new result.
513 * o cmdResultCode (I) - The integer result returned by the command that
514 * Tcl_Eval just completed. Should be TCL_OK if not called from
517 * o tclReceivedSignal (I/O) - Will be cleared.
518 * o signalsReceived (I/O) - The count of each signal that was received.
520 * Either the original result code, an error result if one of the
521 * trap commands returned an error, or an error indicating the
523 *-----------------------------------------------------------------------------
526 Tcl_CheckForSignal (interp
, cmdResultCode
)
531 int signalNum
, result
, sigCnt
, retErrorForSignal
= -1;
533 if (!tclReceivedSignal
)
534 return cmdResultCode
; /* No signal received */
536 savedResult
= ckalloc (strlen (interp
->result
) + 1);
537 strcpy (savedResult
, interp
->result
);
538 Tcl_ResetResult (interp
);
540 for (signalNum
= 1; signalNum
< MAXSIG
; signalNum
++) {
541 if (signalsReceived
[signalNum
] == 0)
544 if (signalTrapCmds
[signalNum
] == NULL
) {
545 retErrorForSignal
= signalNum
;
546 signalsReceived
[signalNum
] = 0;
548 sigCnt
= signalsReceived
[signalNum
];
549 signalsReceived
[signalNum
] = 0;
551 while (sigCnt
-- > 0) {
552 result
= EvalTrapCode (interp
, signalNum
,
553 signalTrapCmds
[signalNum
]);
554 if (result
== TCL_ERROR
)
560 if (retErrorForSignal
>= 0) {
564 * Force name to always be SIGCHLD, even if system defines only SIGCLD.
566 if (retErrorForSignal
== SIGCHLD
)
567 signalName
= "SIGCHLD";
569 signalName
= Tcl_SignalId (retErrorForSignal
);
571 Tcl_SetErrorCode (interp
, "UNIX", "SIG", signalName
, (char*) NULL
);
572 Tcl_AppendResult (interp
, signalName
, " signal received",
574 Tcl_SetVar (interp
, "errorInfo", "", TCL_GLOBAL_ONLY
);
577 Tcl_SetResult (interp
, savedResult
, TCL_DYNAMIC
);
579 result
= cmdResultCode
;
583 if (savedResult
!= NULL
)
584 ckfree (savedResult
);
586 * An error might have caused clearing of some signal flags to be missed.
593 *-----------------------------------------------------------------------------
597 * Parse a list of signal names or numbers.
600 * o interp (O) - Interpreter for returning errors.
601 * o signalListStr (I) - The Tcl list of signals to convert.
602 * o signalList (O) - The list of converted signal numbers, must be
603 * big enough to hold MAXSIG signals.
604 * Tcl_Eval just completed.
606 * The number of signals converted, or -1 if an error occures.
607 *-----------------------------------------------------------------------------
610 ParseSignalList (interp
, signalListStr
, signalList
)
615 char **signalListArgv
;
616 int signalListSize
, signalNum
, idx
;
620 if (Tcl_SplitList (interp
, signalListStr
, &signalListSize
,
621 &signalListArgv
) != TCL_OK
)
624 if (signalListSize
> MAXSIG
) {
625 Tcl_AppendResult (interp
, "too many signals supplied in list",
630 if (signalListSize
== 0) {
631 Tcl_AppendResult (interp
, "signal list may not be empty",
636 for (idx
= 0; idx
< signalListSize
; idx
++) {
637 signalName
= signalListArgv
[idx
];
639 if (Tcl_StrToInt (signalName
, 0, &signalNum
))
640 signalName
= Tcl_SignalId (signalNum
);
642 signalNum
= SigNameToNum (signalName
);
644 if (signalName
== NULL
) {
647 sprintf (numBuf
, "%d", signalNum
);
648 Tcl_AppendResult (interp
, "invalid signal number: ",
649 numBuf
, (char *) NULL
);
653 if ((signalNum
< 1) || (signalNum
> NSIG
)) {
654 Tcl_AppendResult (interp
, "invalid signal name: ",
655 signalName
, (char *) NULL
);
658 signalList
[idx
] = signalNum
;
661 result
= signalListSize
;
663 ckfree ((char *) signalListArgv
);
669 *-----------------------------------------------------------------------------
673 * Determine if a signal is blocked. On non-Posix systems, always returns
677 * o interp (O) - Error messages are returned in result.
678 * o signalNum (I) - The signal to determine the state for.
680 * NULL if an error occured, or a pointer to a static string of "1" if the
681 * signal is block, and a static string of "0" if it is not blocked.
682 *-----------------------------------------------------------------------------
685 SignalBlocked (interp
, signalNum
)
691 sigset_t sigBlockSet
;
693 if (sigprocmask (SIG_BLOCK
, NULL
, &sigBlockSet
)) {
694 interp
->result
= Tcl_UnixError (interp
);
697 return sigismember (&sigBlockSet
, signalNum
) ? "1" : "0";
704 *-----------------------------------------------------------------------------
708 * Return a keyed list containing the signal states for the specified
712 * o interp (O) - The list is returned in the result.
713 * o signalListSize (I) - Number of signals in the signal list.
714 * o signalList (I) - List of signals of requested signals.
716 * TCL_OK or TCL_ERROR, with error message in interp.
717 *-----------------------------------------------------------------------------
720 GetSignalStates (interp
, signalListSize
, signalList
)
723 int signalList
[MAXSIG
];
725 int idx
, signalNum
, actuallyDone
= -1;
726 char *stateKeyedList
[MAXSIG
];
727 char *sigState
[3], *sigEntry
[2];
728 signalProcPtr_t actionFunc
;
730 for (idx
= 0; idx
< signalListSize
; idx
++) {
731 signalNum
= signalList
[idx
];
733 actionFunc
= GetSignalState (signalNum
);
734 if (actionFunc
== SIG_ERR
)
738 if (actionFunc
== SIG_DFL
)
739 sigState
[0] = "default";
740 else if (actionFunc
== SIG_IGN
)
741 sigState
[0] = "ignore";
742 else if (actionFunc
== TclSignalTrap
) {
743 if (signalTrapCmds
[signalNum
] == NULL
)
744 sigState
[0] = "error";
746 sigState
[0] = "trap";
747 sigState
[2] = signalTrapCmds
[signalNum
];
751 sigState
[1] = SignalBlocked (interp
, signalNum
);
752 if (sigState
[1] == NULL
)
755 sigEntry
[0] = Tcl_SignalId (signalNum
);
756 sigEntry
[1] = Tcl_Merge ((sigState
[2] == NULL
) ? 2 : 3,
759 stateKeyedList
[idx
] = Tcl_Merge (2, sigEntry
);
760 ckfree (sigEntry
[1]);
765 Tcl_SetResult (interp
, Tcl_Merge (signalListSize
, stateKeyedList
),
768 for (idx
= 0; idx
<= actuallyDone
; idx
++)
769 ckfree (stateKeyedList
[idx
]);
774 for (idx
= 0; idx
<= actuallyDone
; idx
++)
775 ckfree (stateKeyedList
[idx
]);
777 interp
->result
= Tcl_UnixError (interp
);
782 *-----------------------------------------------------------------------------
786 * Set the signal state for the specified signals.
789 * o interp (O) - The list is returned in the result.
790 * o signalListSize (I) - Number of signals in the signal list.
791 * o signalList (I) - List of signals of requested signals.
792 * o actionFunc (I) - The function to run when the signal is received.
793 * o command (I) - If the function is the "trap" function, this is the
794 * Tcl command to run when the trap occurs. Otherwise, NULL.
796 * TCL_OK or TCL_ERROR, with error message in interp.
797 *-----------------------------------------------------------------------------
800 SetSignalStates (interp
, signalListSize
, signalList
, actionFunc
, command
)
803 int signalList
[MAXSIG
];
804 signalProcPtr_t actionFunc
;
808 int idx
, signalNum
, commandLen
;
811 commandLen
= strlen (command
);
813 for (idx
= 0; idx
< signalListSize
; idx
++) {
814 signalNum
= signalList
[idx
];
816 if (signalTrapCmds
[signalNum
] != NULL
) {
817 ckfree (signalTrapCmds
[signalNum
]);
818 signalTrapCmds
[signalNum
] = NULL
;
820 if (!SetSignalAction (signalNum
, actionFunc
))
823 if (command
!= NULL
) {
824 signalTrapCmds
[signalNum
] = ckalloc (commandLen
+ 1);
825 strcpy (signalTrapCmds
[signalNum
], command
);
832 interp
->result
= Tcl_UnixError (interp
);
837 *-----------------------------------------------------------------------------
841 * Block or unblock the specified signals. Returns an error if not a Posix
845 * o interp (O) - Error messages are returned in result.
846 * o action (I) - SIG_BLOCK or SIG_UNBLOCK.
847 * o signalListSize (I) - Number of signals in the signal list.
848 * o signalList (I) - List of signals of requested signals.
850 * TCL_OK or TCL_ERROR, with error message in interp.
851 *-----------------------------------------------------------------------------
854 BlockSignals (interp
, action
, signalListSize
, signalList
)
858 int signalList
[MAXSIG
];
862 sigset_t sigBlockSet
;
864 sigemptyset (&sigBlockSet
);
866 for (idx
= 0; idx
< signalListSize
; idx
++)
867 sigaddset (&sigBlockSet
, signalList
[idx
]);
869 if (sigprocmask (action
, &sigBlockSet
, NULL
)) {
870 interp
->result
= Tcl_UnixError (interp
);
876 interp
->result
= noPosix
;
882 *-----------------------------------------------------------------------------
885 * Implements the TCL signal command:
886 * signal action siglist [command]
889 * Standard TCL results, may return the UNIX system error message.
892 * Signal handling states may be changed.
893 *-----------------------------------------------------------------------------
896 Tcl_SignalCmd (clientData
, interp
, argc
, argv
)
902 int signalListSize
, signalNum
, idx
;
903 int signalList
[MAXSIG
], actionClass
;
905 signalProcPtr_t actionFunc
;
906 char *command
= NULL
;
908 if ((argc
< 3) || (argc
> 4)) {
909 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
910 " action signalList [commands]", (char *) NULL
);
914 signalListSize
= ParseSignalList (interp
, argv
[2], signalList
);
915 if (signalListSize
< 0)
919 * Determine the action to take on all of the signals.
921 if (STREQU (argv
[1], "trap")) {
922 actionFunc
= TclSignalTrap
;
923 actionClass
= SIGACT_SET
;
925 Tcl_AppendResult (interp
, "command required for ",
926 "trapping signals", (char *) NULL
);
931 if (STREQU (argv
[1], "default")) {
932 actionFunc
= SIG_DFL
;
933 actionClass
= SIGACT_SET
;
934 } else if (STREQU (argv
[1], "ignore")) {
935 actionFunc
= SIG_IGN
;
936 actionClass
= SIGACT_SET
;
937 } else if (STREQU (argv
[1], "error")) {
938 actionFunc
= TclSignalTrap
;
939 actionClass
= SIGACT_SET
;
940 } else if (STREQU (argv
[1], "get")) {
941 actionClass
= SIGACT_GET
;
942 } else if (STREQU (argv
[1], "block")) {
943 actionClass
= SIGACT_BLOCK
;
944 } else if (STREQU (argv
[1], "unblock")) {
945 actionClass
= SIGACT_UNBLOCK
;
947 Tcl_AppendResult (interp
, "invalid signal action specified: ",
948 argv
[1], ": expected one of \"default\", ",
949 "\"ignore\", \"error\", \"trap\", or \"get\", ",
950 "\"block\", \"unblock\"", (char *) NULL
);
954 Tcl_AppendResult (interp
, "command may not be ",
955 "specified for \"", argv
[1], "\" action",
962 * Process the specified action class.
964 switch (actionClass
) {
966 return SetSignalStates (interp
, signalListSize
, signalList
,
967 actionFunc
, command
);
969 return GetSignalStates (interp
, signalListSize
, signalList
);
971 return BlockSignals (interp
, SIG_BLOCK
, signalListSize
, signalList
);
973 return BlockSignals (interp
, SIG_UNBLOCK
, signalListSize
, signalList
);
979 *-----------------------------------------------------------------------------
981 * SignalCmdCleanUp --
982 * Clean up the signal table when the interpreter is deleted. This
983 * is actually when the signal command is deleted. It releases the
984 * all signal commands that have been allocated.
986 *-----------------------------------------------------------------------------
989 SignalCmdCleanUp (clientData
)
990 ClientData clientData
;
994 for (idx
= 0; idx
< MAXSIG
; idx
++)
995 if (signalTrapCmds
[idx
] != NULL
) {
996 ckfree (signalTrapCmds
[idx
]);
997 signalTrapCmds
[idx
] = NULL
;
1003 *-----------------------------------------------------------------------------
1005 * Tcl_InitSignalHandling --
1006 * Initializes the TCL unix commands.
1009 * A catch trap is armed for the SIGINT signal.
1011 *-----------------------------------------------------------------------------
1014 Tcl_InitSignalHandling (interp
)
1019 for (idx
= 0; idx
< MAXSIG
; idx
++) {
1020 signalsReceived
[idx
] = 0;
1021 signalTrapCmds
[idx
] = NULL
;
1023 Tcl_CreateCommand (interp
, "kill", Tcl_KillCmd
, (ClientData
)NULL
,
1025 Tcl_CreateCommand (interp
, "signal", Tcl_SignalCmd
, (ClientData
)NULL
,
1028 * If interrupt is currently being trapped, enabled it. Other wise
1029 * leave it off, or if this process is running as a background job it will
1030 * get its parent's (shell's) signals.
1032 if (GetSignalState (SIGINT
) != SIG_IGN
)
1033 SetSignalAction (SIGINT
, TclSignalTrap
);