The problem there is that I don't think that argc exists as a pointer anywhere: only as a scalar. So the best that could be done would be something like:
* In /var/run, the long-running program sets up a block of shm (mmap in appropriate places in what follows).
* At the start of this it writes pid followed by /n and some zero padding and a magic number, so that it looks like a conventional pid file.
* Once its finished processing its own options and parameters, it changes argv to point (say) 512 bytes into the shm block and zeroes argc.
* A newly-started program with e.g. RESTART as its final parameter checks the shm block's magic number then sets up a ppchar 512 bytes into it and copies its options and parameters.
* The newly-started program then sends a SIGHUP using sigqueue() to the pid in the shm block, passing its argc as the integer parameter.
* The long-running process copies the integer parameter into argc. From that point ParamCount() and ParamStr() should just work.
I tweaked an existing signal handler yesterday morning to look like this:
var sigNo, sigErr, sigCode, sigPid: integer; (* For debugging *)
sigVal: ptruint;
(* We don't ever want to screw the MCP by responding to a casual ^C. We do,
however, want to do our best to shut down in good order if we get an urgent
signal such as SIGTERM, since it might indicate an incipient power failure.
*)
procedure termHandler(sig: longint; info: PSigInfo; context: PSigContext); cdecl;
const
SI_USER= 0; (* sent by kill, sigsend, raise *)
SI_KERNEL= $80; (* sent by the kernel from somewhere *)
SI_QUEUE= -1; (* sent by sigqueue *)
SI_TIMER= -2; (* sent by timer expiration *)
SI_MESGQ= -3; (* sent by real time mesq state change *)
SI_ASYNCIO= -4; (* sent by AIO completion *)
SI_SIGIO= -5; (* sent by queued SIGIO *)
SI_TKILL= -6; (* sent by tkill system call *)
SI_DETHREAD= -7; (* sent by execve() killing subsidiary threads *)
SI_ASYNCNL= -60; (* sent by glibc async name lookup completion *)
begin
with info^ do begin (* For debugging *)
sigNo := si_signo;
sigErr := si_errno;
sigCode := si_code; (* See SI_USER, SI_QUEUE etc. above *)
sigPid := _sifields._kill._pid;
sigVal := ptruint(_sifields._rt._sigval) (* Used by sigqueue but not by kill *)
end;
case sig of
{ TODO : Trouble here: ^C kills radio process even if close is cancelled. }
SIGINT: shutdown := true;
SIGUSR1: dumpDebug := true;
SIGUSR2,
SIGHUP,
{ TODO : Receiver process restart stuff. See https://man7.org/linux/man-pages/man3/sigqueue.3.html
which might be useful as a way of passing parameters in lieu of a command line
or .ini file. }
// kill -q can pass an integer, killall has no provision for this.
SIGQUIT,
SIGTERM,
SIGPWR: begin
end
otherwise
end
end { termHandler } ;
Noting that that implies an extension to what the RTL documents regarding PSigInfo etc. However I've not tested it yet, and won't be at least until I investigate some process group stuff.
In practice, the process group stuff is far more pressing: I've got a background program running via a TProcess which in some cases I want to be able to restart and in other cases (e.g. if I SIGINT the foreground program but change my mind) I definitely don't want to interfere with.
And allowing that the pressing issue is to be able to change the gain background process's signal path, there's lots of better ways of moving commands around including- obviously- a menu entry or control on the frontend GUI.
MarkMLl