Opened 20 months ago

Closed 5 months ago

#7229 closed bug (fixed)

Detecting if a process was killed by a signal is impossible

Reported by: benmachine Owned by:
Priority: highest Milestone: 7.8.1
Component: libraries/process Version:
Keywords: Cc: andersk@…, anton.nik@…, dcoutts
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

Currently there is no good way of detecting if a process was terminated by a signal. We have the following problems:

  • Firstly, the API doesn't make any allowance for it. This may be because the concept doesn't exist on Windows, I'm not sure. But since the concept does exist on POSIX, we do have to make a decision about what to do there (or if we have made one, document it).
  • waitForProcess attempts to give the signal in the exit code, but the underlying C function doesn't use the WTERMSIG macro. It so happens that on my system it works fine anyway, but it has no right to in principle (and in any case, what it does is both sub-optimal (in that getting killed by SIGINT is indistinguishable from returning 3) and undocumented).
  • The C function getProcessExitCode is much worse. When a process has exited due to a signal, it tests WIFSIGNALED, and if true, sets errno = EINTR (huh?) and returns -1. Since it is called from throwErrnoIfMinus1Retry, the result is that it immediately gets called again: but this time the child doesn't exist anymore. The behaviour in the case of ECHILD is, bizarrely, to pretend that there was a child and it exited with status 0, i.e. success. Which is just untrue.

I don't know what the right behaviour is, but the above is both inconsistent and unhelpful. The lack of WTERMSIG is easily fixed, but that's the least of the problems here: we really need to work out what ought to happen before we start making it happen.

Change History (41)

comment:1 Changed 20 months ago by andersk

  • Cc andersk@… added

comment:2 Changed 19 months ago by lelf

  • Cc anton.nik@… added

comment:3 Changed 19 months ago by simonmar

  • Difficulty set to Unknown
  • Milestone set to 7.6.2
  • Priority changed from normal to high

I have adopted the shell convention of using 128 + signal number as the exit status for a process that died due to a signal. Symbolic constants for the signal names are available from System.Posix.Signals. I've also fixed the slightly strange behaviour of getProcessExitCode - I dug through the logs a bit, but the current code goes back a long way and I couldn't find the reason for fixing EINTR.

Would anyone object to this going into 7.6.2? There is a semantic change, but it is very unlikely that anyone was depending on the old behaviour. We would need a minor version bump to process so that clients can conditionally depend on the new behaviour.

patches to process package:

commit 54038240284b11ad4117ca075fa2292f5069bc45
Author: Simon Marlow <marlowsd@gmail.com>
Date:   Mon Sep 24 09:50:24 2012 +0100

    Use (128+signal) as the exit code when a proc terminates due to a signal (#7229)

commit 9547cf40ac1ddcd471a8ce75f927b382a82c1038
Author: Simon Marlow <marlowsd@gmail.com>
Date:   Mon Sep 24 12:11:14 2012 +0100

    Test for #7229

commit 007fb056f2e77e65196de4bff94ea001e69a12eb
Author: Simon Marlow <marlowsd@gmail.com>
Date:   Mon Sep 24 12:27:43 2012 +0100

    Documentation for signal exit codes (#7229)

comment:4 Changed 19 months ago by andersk

While that’s a small improvement over the previous undocumented behavior, it’s still not a real solution. In Unix programming, it’s important to be able to reliably distinguish between WIFEXITED(status) (e.g. exit(130)) and WIFSIGNALED(status) (e.g. raise(SIGINT)), so that one can implement WCE (wait and cooperative exit) on SIGINT. The 128 + signal thing that you see in your shell is specific to your shell; real languages do make this distinction.

Really the right answer is to add a constructor to ExitCode. While we’re doing that, we should expose WCOREDUMP(status) for completeness: ExitSignaled {exitSignal :: Int, exitCoreDump :: Bool}.

comment:5 Changed 19 months ago by benmachine

Thanks Simon, that's certainly an improvement. I'm inclined to agree with andersk that it's not the principled solution.

My man page for WCOREDUMP says

       WCOREDUMP(status)
              returns  true  if  the  child produced a core dump.  This macro
              should only be employed if  WIFSIGNALED  returned  true.   This
              macro  is not specified in POSIX.1-2001 and is not available on
              some UNIX implementations (e.g., AIX, SunOS).   Only  use  this
              enclosed in #ifdef WCOREDUMP ... #endif.

I don't know how worried we are about that.

comment:6 follow-up: Changed 19 months ago by simonmar

Ok, points taken. 128+signal is not good, because that overlaps with exit codes.

Unfortunately we can't add the right information to ExitCode, because it is a platform-independent type. The correct type already exists: it is called System.Posix.ProcessStatus.

data ProcessStatus = Exited ExitCode
                   | Terminated Signal
                   | Stopped Signal
		   deriving (Eq, Ord, Show)

Unfortunately whoever wrote this forgot to add a Bool to indicate a core dump in the Terminated constructor. We *could* fix that.

Now, the right thing to do would be to create a new process-unix package containing

module System.Process.Posix where
waitForProcess :: ProcessHandle -> IO ProcessStatus
getProcessStatus :: ProcessHandle -> IO (Maybe ProcessStatus)

It can't be part of the process package because the API of a package cannot differ depending on the platform. It could be part of the unix package, but then we have to move a chunk of code from the process package into the unix package, which is annoying.

I propose as an intermediate solution that we just fix the ExitCode encoding: instead of 128+signal, use (signal << 8) + exit code, with a core dump setting the 0x8000 bit.

comment:7 follow-up: Changed 19 months ago by andersk

Waah… that’s going to confuse anyone who knows that the real encoding is (exit code << 8) + signal (which, say, Perl forces you to learn). If that’s what we end up with, I guess that difference ought to be noted in the documentation.

I’m not sure I see the problem with an extra constructor that’s unused on non-Unix, but other than that I don’t really have anything else to propose.

comment:8 Changed 19 months ago by benmachine

I'm happy with Simon's solution (one aspect that confuses me: if you're terminated by signal 3, you get (3 << 8) + exit code: what's exit code?) but I'd be happier still, I think, with an extra constructor that's unused on Windows. It just seems that in practice that's what people will write in their code anyway, using a suitable ExitCode -> Either Signal Int function (or, well, Either Int Int, to be portable against the case of Signal not existing)

comment:9 Changed 19 months ago by simonmar

  • Cc dcoutts added

Duncan and I discussed this on IRC, and came up with the following API:

http://community.haskell.org/~simonmar/process-7229/System-Process.html#g:4

The rationale here is:

  • We don't want to change ExitCode for a couple of reasons: first, it is baked into Haskell 2010 and therefore difficult to change; second, it is really intended to be "exit codes you can pass to exitWith", so adding a terminated value wouldn't make much sense there.
  • We want to make it possible to obtain the full platform-specific info (e.g. ProcessStatus) out of the exit status. Making an abstract type for ExitStatus allows us to do this in the future, by building separate platform-specific packages on top of process.


  • Clients can portably ask whether a process was terminated, but this will always return Nothing on non-Unix systems.

I think wasTerminated is a bit clunky, the cases for "exited with an ExitCode?" and "terminated" should really be mutually exclusive. But we'd have to add another type to express that, which is perhaps going too far.

comment:10 Changed 19 months ago by andersk

Actually, passing a signal to exitWith would make perfect sense as a way to re-raise the same signal. This is what bash does when its last child (or with -e, any child) is terminated, for example. If ExitCode won’t change, a portable exitWithStatus :: ExitStatus -> IO a that’s capable of re-raising the same signal on Unix would be useful.

Can we use CInt instead of Int so that comparing with constants in System.Posix.Signals doesn’t require a cast? Or just arrange for ExitStatus to be the same as System.Posix.Process.ProcessStatus when applicable?

comment:11 follow-up: Changed 19 months ago by simonmar

Using exitWith (ExitTerminated signal) as a way to kill the current process with a signal is an attractive idea indeed.

We would have to move the existing ExitCode datatype into the haskell2010 package, and do the corresponding refactorings.

Would we do this in addition to the ExitStatus changes, or instead of them? Another alternative is to provide a unix-specific way to get a ProcessId from a ProcessHandle, and then the unix-specific wait functions can be used to get a ProcessStatus.

Duncan, what do you think?

comment:12 Changed 17 months ago by igloo

  • Milestone changed from 7.6.2 to 7.8.1

comment:13 Changed 5 months ago by hvr

...is the current HEAD of process in a releasable state with respect to this ticket?

comment:14 Changed 5 months ago by andersk

It looks like the current HEAD still uses the ambiguous (128 + signal) return codes from comment:3. I don’t pretend to speak for the developers, but from the following comments it looks like everyone agrees that committing to this API would be a mistake.

comment:15 in reply to: ↑ 6 Changed 5 months ago by hvr

Replying to simonmar:

Unfortunately we can't add the right information to ExitCode, because it is a platform-independent type. The correct type already exists: it is called System.Posix.ProcessStatus.

data ProcessStatus = Exited ExitCode
                   | Terminated Signal
                   | Stopped Signal
                   deriving (Eq, Ord, Show)

Unfortunately whoever wrote this forgot to add a Bool to indicate a core dump in the Terminated constructor. We *could* fix that.

for the record, this has been implemented in [dc29d55b30d95f0838499fb48217e1d22e39d07d/unix] (which is included in the recently released unix-2.7.0.0)

comment:16 in reply to: ↑ 7 Changed 5 months ago by hvr

Replying to andersk:

that’s going to confuse anyone who knows that the real encoding is (exit code << 8) + signal (which, say, Perl forces you to learn).

btw, what do you mean by real encoding?

I've looked a bit around and here's what I've found so far:

Python's os.wait() operation which seem to match Perl's encoding:

... exit status indication: a 16-bit number, whose low byte is the signal number that killed the process, and whose high byte is the exit status (if the signal number is zero); the high bit of the low byte is set if a core file was produced.

...otoh, Wikipedia says regarding POSIX Exit status:

... SUS specifies that the low-order 8 bits of the status value contain the exit status ...

comment:17 Changed 5 months ago by andersk

Wikipedia is confused. (I went and fixed it.) If you go actually read the specification, you see

WEXITSTATUS(stat_val): … this macro evaluates to the low-order 8 bits of the status argument that the child process passed to _exit() or exit(), or the value the child process returned from main().

and also

The status values are retrieved by macros, rather than given as specific bit encodings as they are in most historical implementations (and thus expected by existing programs). This was necessary to eliminate a limitation on the number of signals an implementation can support that was inherent in the traditional encodings.

Here’s the definition from glibc:

/* If WIFEXITED(STATUS), the low-order 8 bits of the status.  */
#define __WEXITSTATUS(status)   (((status) & 0xff00) >> 8)

/* If WIFSIGNALED(STATUS), the terminating signal.  */
#define __WTERMSIG(status)      ((status) & 0x7f)

which is to say that bits 8-15 of the wait()/waitpid() status are bits 0-7 of the exit() status (the rest of the exit() status being thrown away), and bits 0-6 of the wait()/waitpid() status are the signal number. This agrees with the Perl/Python? encoding (because, of course, that’s where the Perl/Python? encoding came from).

Last edited 5 months ago by andersk (previous) (diff)

comment:18 follow-up: Changed 5 months ago by hvr

Ok, in summary I see the following possibilities for the return value of the existing waitForProcess call on POSIX systems:

  1. Use the reserved ExitFailure 0 value to denote WIFEXITED(s) == FALSE; code should use the new API functions from comment:9 if it's interested in getting better exit-status information
  1. Use the Perl/Python? encoding convention for the argument of ExitFailure, i.e.
    if coredump then 0x0080 else 0 .|. exit-status `shift` 8 .|. signum
    
    causes impedance mismatch with the Haskell2010's exitWith
  1. Use Bash-encoding for the argument of ExitFailure causes impedance mismatch with Haskell2010's exitWith; issue with exit-codes > 0x7f and core-dump flag
  1. Use byte-swapped version of 2. (as suggested by Simon)

I'm somewhat inclined to go with 1.; 2. would be tolerable if exitWith in base is adapted to interpret the exit code in the same way

Last edited 5 months ago by hvr (previous) (diff)

comment:19 follow-up: Changed 5 months ago by andersk

Adding constructors to ExitCode seems to still be an option (comment:10, comment:11). I think that would make all the other proposed changes unnecessary.

comment:20 in reply to: ↑ 19 Changed 5 months ago by hvr

Replying to andersk:

Adding constructors to ExitCode seems to still be an option (comment:10, comment:11). I think that would make all the other proposed changes unnecessary.

that change would involve modifications to haskell2010, base, process and maybe unix if I understand it right... :-/

comment:21 in reply to: ↑ 11 Changed 5 months ago by hvr

Replying to simonmar:

We would have to move the existing ExitCode datatype into the haskell2010 package, and do the corresponding refactorings.

...what's exactly involved here?

Does this mean, that haskell2010 (as well as haskell98) gets a distinct System.Exit.ExitCode type (but with the same name) as the one remaining in base?

comment:22 Changed 5 months ago by duncan

What would exitWith (ExitTerminated signal) mean on Windows?

Having the abstract ExitStatus type as Simon and I proposed would not have that issue, since it's only for the reading side, not the throwing side, and on Windows can always return Nothing.

My view is still that using a structured type is a lot nicer than using a bit twiddling encoding. Related to this is that we want an extra CreateProcess option to do the WCE automatically. We still have the mad situation that System.Cmd can mask ctl-c for us, but System.Process lacks that feature.

comment:23 Changed 5 months ago by andersk

I guess you could replace ExitTerminated CInt Bool with ExitTerminated Signal Bool, where Signal is CInt on POSIX and Void on Windows? (And/or there’s a platform-independent Signal -> CInt and a POSIX-dependent CInt -> Signal?)

comment:24 Changed 5 months ago by duncan

So on reflection, I think I'm changing my opinion.

The H2010 docs say: "The exact interpretation of the code is operating-system dependent."

So on that principle then I think we're well justified to use a reasonable encoding. This also means we don't have the trouble of braking existing code by adding a new ExitCode constructor. Existing code that doesn't interpret the exit code much will continue to work.

As for the specific encoding. It would be madness for us to use the low bits for the signal. There must be plenty of code out there that looks for ExitFailure 1 or other low numbers for example. So we would have to use Simon's encoding, high bits for a signal, low bits for a normal exit.

I suggest we update the ExitCode docs to indicate how the Int corresponds to the system exit code on Windows and Unix (ie directly for Windows and the high 8 signal & low 8 normal exit code encoding for Unix).

hvr raises a related question:

  • What should we do for exitWith (ExitFailure n) for n > 255 on Unix?

Currently the code just takes the low 8 bits. This is clearly silly since it would end up being equiv to exitWith ExitSuccess. Using numbers > 255 is fine on Windows.

In addition, if we are going to use 16 bits for the exit code on Unix then we ought to be able to use exitWith on such values.

So, how about this for a specific suggestion:

  • On unix, use 16bits of the ExitFailure Int, high 8 for signal, low 8 for normal exit code.
  • waitForProcess & getProcessExitCode return this encoding on Unix.
  • It is valid to exitWith an ExitCode from waitForProcess & getProcessExitCode and the top level handler should make this have the appropriate behaviour:
    • calling exit(n); or
    • calling kill(getpid(), s);
  • These are mutually exclusive. That is, we either get non-0 high byte or non-0 low byte but never both.
    • We enforce this on the exitWith side. An invalid encoding is replaced with ExitFailure 255. So that's used if both exit code + signal are set, or if it's > 16bit, or negative. But we do not make it an error because we don't want to create needless portability problems for programs using high Windows error codes.

comment:25 Changed 5 months ago by duncan

hvr points out it's actually only 7bits for the signal, not 8.

I can't bring myself to care about the core dump bit in this interface. I'm quite happy with leaving that for the unix package.

comment:26 Changed 5 months ago by duncan

See libraries/base/GHC/TopHandler.lhs and rts/RtsStartup.c

comment:27 Changed 5 months ago by simonmar

Sounds like this discussion is converging. I'm happy with the proposal to encode signals in bits 8-15 of the exit code, and to have exitWith call kill() when given one of these signal codes.

comment:28 in reply to: ↑ 18 Changed 5 months ago by hvr

Replying to hvr:

Ok, in summary I see the following possibilities for the return value of the existing waitForProcess call on POSIX systems:

...

  1. PS/Just for the record: it would also be possible (since WIFEXITED(s) and WIFSIGNALED(s) are mutually exclusive) to encode signals as negative integers

comment:29 Changed 5 months ago by hvr

So, the implementation of the last proposal ammmounts to two simple modifications:

a patch to process:

  • cbits/runProcess.c

    diff --git a/cbits/runProcess.c b/cbits/runProcess.c
    index 3462cfc..3a6f2f3 100644
    a b  
    2222   UNIX versions 
    2323   ------------------------------------------------------------------------- */ 
    2424 
    25 // 
    26 // If a process terminates with a signal, the exit status we return to 
    27 // via the System.Process API follows the Unix shell convention of 
    28 // (128 + signal). 
    29 // 
    30 #define TERMSIG_STATUS(r) ((r) | 0x80) 
     25// If a process was terminated by a signal, the exit status we return 
     26// via the System.Process API is (signum << 8); this avoids collision 
     27// with normal process termination status codes, as according to 
     28// http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html 
     29// WEXITSTATUS(s) returns an 8-bit value. See also #7229. 
     30#define TERMSIG_STATUS(r) (r << 8) 
    3131 
    3232static long max_fd = 0; 

...and a patch for base (provided by duncan):

  • GHC/TopHandler.lhs

    diff --git a/GHC/TopHandler.lhs b/GHC/TopHandler.lhs
    index 9e4bc07..b0c5d0d 100644
    a b flushStdHandles = do 
    180180-- we have to use unsafeCoerce# to get the 'IO a' result type, since the 
    181181-- compiler doesn't let us declare that as the result type of a foreign export. 
    182182safeExit :: Int -> IO a 
     183#ifdef mingw32_HOST_OS 
    183184safeExit r = unsafeCoerce# (shutdownHaskellAndExit $ fromIntegral r) 
     185#else 
     186-- On Unix we use an encoding for the ExitCode: 
     187--   high 7 bits signal, low 8 bits normal exit code. 
     188-- People can also use ExitCode that do not correspond to Unix exit() 
     189-- codes and we just use a replacement. 
     190safeExit r 
     191  | sig /= 0 && code == 0 && other == 0 
     192  = unsafeCoerce# (shutdownHaskellAndSignal $ fromIntegral sig) 
     193  | sig == 0              && other == 0 
     194  = unsafeCoerce# (shutdownHaskellAndExit $ fromIntegral code) 
     195  | otherwise 
     196  = unsafeCoerce# (shutdownHaskellAndExit 0xff) 
     197  where 
     198    sig   = (r .&. 0x7f00) `shiftR` 8 
     199    code  =  r .&. 0x00ff 
     200    other =  r .&. (complement 0x7fff) 
     201#endif 

If there are no objections left, I'll apply the changes above, validate (tweaking the testsuite if necessary) and push the changes.

comment:30 follow-up: Changed 5 months ago by andersk

Ugly but acceptable; I’m happy to come to a resolution on this issue, provided

  • The documentation clearly calls out that our encoding is byte-swapped from the standard one for historical reasons.
  • We might as well include the core dump bit as bit 15 for completeness. It’s useful for printing messages like Segmentation fault (core dumped), and I don’t see a downside as long as we do it now. glibc, Perl, and Python all provide it as bit 7.

comment:31 in reply to: ↑ 30 Changed 5 months ago by hvr

Replying to andersk:

  • The documentation clearly calls out that our encoding is byte-swapped from the standard one for historical reasons.

Yeah, I've planned to enhance the documentation related to exitWith, and for the two functions in process to reflect the new non-windows encoding.

  • We might as well include the core dump bit as bit 15 for completeness. It’s useful for printing messages like Segmentation fault (core dumped), and I don’t see a downside as long as we do it now. glibc, Perl, and Python all provide it as bit 7.

...I'm not against that, but what should safeExit do in that case? with the current patch this would cause other /= 0 and thus terminate normally with exit code 255.

comment:32 follow-up: Changed 5 months ago by andersk

safeExit should just ignore the coredump flag for the shutdownHaskellAndSignal case. (The process can’t control whether the SIG_DFL action for that signal results in a core dump—the list of such signals is defined by the kernel, e.g. SIG_KERNEL_COREDUMP_MASK in Linux.)

Last edited 5 months ago by andersk (previous) (diff)

comment:33 in reply to: ↑ 32 Changed 5 months ago by hvr

Replying to andersk:

safeExit should just ignore the coredump flag. (The process can’t control whether the SIG_DFL action for that signal results in a core dump—the list of such signals is defined by the kernel, e.g. SIG_KERNEL_COREDUMP_MASK in Linux.)

ok, so

  • safeExit 0x8300 would be handled like safeExit 0x0300

but what should happen for the corner-cases

  • safeExit 0x8000, or
  • safeExit 0x8001, or
  • safeExit 0x18000

?

comment:34 Changed 5 months ago by andersk

I’d say we reject those corner cases and turn them into 0xff like other unexpected values—we only allow the coredump flag in the signal case. (I don’t care strongly.)

comment:35 Changed 5 months ago by duncan

Here's my updated patch. Totally untested

  • GHC/TopHandler.lhs

    diff --git a/GHC/TopHandler.lhs b/GHC/TopHandler.lhs
    index 9e4bc07..8953334 100644
    a b flushStdHandles = do 
    180180-- we have to use unsafeCoerce# to get the 'IO a' result type, since the 
    181181-- compiler doesn't let us declare that as the result type of a foreign export. 
    182182safeExit :: Int -> IO a 
     183#ifdef mingw32_HOST_OS 
    183184safeExit r = unsafeCoerce# (shutdownHaskellAndExit $ fromIntegral r) 
     185#else 
     186-- On Unix we use an encoding for the ExitCode: 
     187--   Bits: 0-7  (mask 0x00ff)  normal exit code 
     188--   Bits: 8-14 (mask 0x7f00)  exit by signal 
     189--   Bits: 15   (mask 0x8000)  core dump (allowed with signal but ignored) 
     190-- A normal exit, and exit by signal are mutually exclusive. 
     191-- For any invalid encoding we just use a replacement (0xff). 
     192safeExit r 
     193  | sig /= 0 && code == 0 && other == 0 {-any cdump-} 
     194  = unsafeCoerce# (shutdownHaskellAndSignal $ fromIntegral sig) 
     195  | sig == 0 {-any code-} && other == 0 && cdump == 0 
     196  = unsafeCoerce# (shutdownHaskellAndExit $ fromIntegral code) 
     197  | otherwise 
     198  = unsafeCoerce# (shutdownHaskellAndExit 0xff) 
     199  where 
     200    sig   = (r .&. 0x7f00) `shiftR` 8 
     201    cdump =  r .&. 0x8000 
     202    code  =  r .&. 0x00ff 
     203    other =  r .&. (complement 0xffff) 
     204#endif 
    184205 
    185206exitInterrupted :: IO a 
    186207exitInterrupted =  

comment:36 Changed 5 months ago by duncan

Unclear if we also want to do something with fastExit, as used by runIOFastExit and topHandlerFastExit.

If so, we need an extra function like shutdownHaskellAndSignal but that doesn't do the hs_exit_() call.

comment:37 Changed 5 months ago by hvr

  • Priority changed from high to highest

(just upgrading priority to increase visibility of this ticket)

comment:38 Changed 5 months ago by Herbert Valerio Riedel <hvr@…>

In ffe7773c7fd222a946d17f489020098a45b5c8af/process:

Change exit code encoding of `waitForProcess` yet again

This changes the exit code encoding from `(128+signum)`
(as introduced via 5403824028) to

{{{#!hs
if coredump then 0x8000 else 0 .|. signum `shiftL` 8 .|. exitstatus
}}}

in order to address the `process`-package part of #7229

Signed-off-by: Herbert Valerio Riedel <hvr@gnu.org>

comment:39 Changed 5 months ago by duncan

Heh, turns out python switched to using -N for signals. See popen.

http://docs.python.org/2/library/subprocess.html#subprocess.Popen.returncode

comment:40 Changed 5 months ago by duncan

@andersk just to play devil's advocate for a moment: why not use negative encoding for signals, and just ignore the core dump bit? It gives an encoding that is very simple to use and very few people care about core dumps (and if they do, they can use the unix package).

-n is a lot easier than (n .&. 0x7f00) `shiftR` 8. Indeed people are likely to do it wrong and just use n `shiftR` 8 in which case they'll get tripped up whenever there is a core dump (which is platform configuration specific).

comment:41 Changed 5 months ago by duncan

  • Resolution set to fixed
  • Status changed from new to closed

So I've pushed patches to process, base and the rts to implement this, using the -signum encoding.

There's also haddock docs, and tests (in separate commits). I think we can declare this done.

Note: See TracTickets for help on using tickets.