libposix: initial changes to POSIX_kill

This commit is contained in:
Giacomo Tesio 2017-05-24 00:40:28 +02:00
parent 3381f75d03
commit 68bc46fe85
5 changed files with 110 additions and 39 deletions

View File

@ -22,7 +22,7 @@
extern int *__libposix_errors_codes;
extern WaitList **__libposix_wait_list;
extern Child **__libposix_child_list;
extern ChildList **__libposix_child_list;
static int __initialized;
static void
@ -44,7 +44,7 @@ libposix_init(int argc, char *argv[], PosixInit init)
extern int *__libposix_sigchld_target_pid;
WaitList *wait_list;
Child *child_list;
ChildList *child_list;
int status;
int error_codes[ERRNO_LAST-ERRNO_FIRST];
unsigned char signals_to_code[256];
@ -64,7 +64,7 @@ libposix_init(int argc, char *argv[], PosixInit init)
/* initialize child_list; used when SIGCHLD is enabled */
child_list = nil;
__libposix_wait_list = &child_list;
__libposix_child_list = &child_list;
/* initialize signal handling */
memset(signals_to_code, 0, sizeof(signals_to_code));

View File

@ -23,11 +23,11 @@ struct WaitList
WaitList *next;
};
typedef struct Child Child;
struct Child
typedef struct ChildList ChildList;
struct ChildList
{
int pid;
Child *next;
ChildList *next;
};
extern void __libposix_files_check_conf(void);
@ -48,3 +48,4 @@ extern void __libposix_free_wait_list(void);
extern void __libposix_setup_new_process(void);
extern int __libposix_note_to_signal(char *note);

View File

@ -23,7 +23,7 @@
extern char **environ;
WaitList **__libposix_wait_list;
Child **__libposix_child_list;
ChildList **__libposix_child_list;
static PosixExitStatusTranslator __libposix_exit_status_translator;
static int __libposix_wnohang;
@ -34,7 +34,6 @@ static int
fork_without_sigchld(int *errnop)
{
int pid = fork();
if(pid == 0)
__libposix_setup_new_process();
return pid;
@ -42,14 +41,6 @@ fork_without_sigchld(int *errnop)
int (*__libposix_fork)(int *errnop) = fork_without_sigchld;
void
__libposix_setup_new_process(void)
{
/* reset wait list for the child */
*__libposix_wait_list = nil;
*__libposix_child_list = nil;
}
void
__libposix_free_wait_list(void)
{
@ -69,6 +60,33 @@ __libposix_free_wait_list(void)
}
}
void
__libposix_free_child_list(void)
{
ChildList *l, *c;
/* free the wait list as the memory is shared */
l = *__libposix_child_list;
if(l != nil){
*__libposix_child_list = nil;
do
{
c = l;
l = c->next;
free(c);
}
while (l != nil);
}
}
void
__libposix_setup_new_process(void)
{
/* reset wait list for the child */
__libposix_free_wait_list();
__libposix_free_child_list();
}
void
POSIX_exit(int code)
{

View File

@ -24,7 +24,7 @@
/* rendezvous points */
extern unsigned char *__signals_to_code_map;
extern unsigned char *__code_to_signal_map;
extern Child **__libposix_child_list;
extern ChildList **__libposix_child_list;
/* pointer to the pid to forward notes to */
int *__libposix_sigchld_target_pid;
@ -44,8 +44,24 @@ release_inherited_resources(void)
static void
forwarding_note_handler(void *ureg, char *note)
{
postnote(PNPROC, *__libposix_sigchld_target_pid, note);
noted(NCONT);
int sig;
PosixSignals psig;
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) == 0){
sig = __libposix_note_to_signal(note);
if(sig < __min_known_sig || sig > __max_known_sig){
/* Ignore unknown signals */
noted(NCONT);
}
psig = __code_to_signal_map[sig];
switch(psig){
}
postnote(PNPROC, *__libposix_sigchld_target_pid, note);
noted(NCONT);
} else {
/* what happened? */
noted(NDFLT);
}
}
static void
@ -93,6 +109,7 @@ fork_with_sigchld(int *errnop)
int p2c;
long c2p = -1, child = -1;
char proxy_name[256];
ChildList *c;
/* Father here:
* - create P2C
@ -173,9 +190,11 @@ fork_with_sigchld(int *errnop)
break;
}
/* TODO: register p2c among known children so that kill can
* handle them properly.
*/
/* no need to lock: the child list is private */
c = malloc(sizeof(ChildList));
c->pid = p2c;
c->next = *__libposix_child_list;
*__libposix_child_list = c;
return p2c;
}

View File

@ -69,7 +69,7 @@
* Calling libposix_emulate_SIGCHLD() during libposix initialization
* will enable this machinery for the whole life of the process.
*
* Such emulation change the way fork and kill works.
* Such emulation changes the way POSIX_fork and POSIX_kill works.
*
* Each fork() will spawn two additional processes that are designed
* to proxy signals between the parent and the desired child:
@ -162,7 +162,7 @@ terminated_by_signal(int sig)
}
int
send_control_msg(int pid, char *msg)
__libposix_send_control_msg(int pid, char *msg)
{
int fd, n;
char buf[256];
@ -187,14 +187,13 @@ ErrorBeforeOpen:
return 0;
}
/* Executes a PosixSignalDisposition for pid.
*
* MUST be called by POSIX_kill for unblockable signals.
/* Executes a PosixSignalDisposition.
*/
static int
execute_disposition(int sig, PosixSignalDisposition action, int pid)
execute_disposition(int sig, PosixSignalDisposition action)
{
switch(action){
case ResumeTheProcess: // the sender resumed us already
case SignalHandled:
return 1;
case TerminateTheProcess:
@ -202,17 +201,46 @@ execute_disposition(int sig, PosixSignalDisposition action, int pid)
terminated_by_signal(sig);
break;
case StopTheProcess:
if(pid < 0)
sysfatal("libposix: signal %d with stop disposition reached process %d", sig, pid);
return send_control_msg(pid, "stop");
case ResumeTheProcess:
if(pid < 0)
sysfatal("libposix: signal %d with continue disposition reached process %d", sig, pid);
return send_control_msg(pid, "start");
return __libposix_send_control_msg(getpid(), "stop");
}
return 0;
}
PosixError
__libposix_receive_signal(int sig)
{
if(__libposix_signal_trampoline(sig))
action = SignalHandled;
else
action = default_signal_disposition(sig);
if(!execute_disposition(sig, action))
return PosixEPERM;
return 0;
}
PosixError
__libposix_notify_signal_to_process(int pid, int signal)
{
char buf[128];
int fd, n;
snprint(buf, sizeof(buf), "/proc/%d/note", pid);
if(access(file, AWRITE) != 0){
if(access(file, AEXIST) == 0)
return PosixEPERM;
else
return PosixESRCH;
}
fd = open(buf, OWRITE);
if(fd < 0)
return PosixEPERM;
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal);
write(fd, buf, n);
close(fd);
return 0;
}
static int
send_signal(int *errnop, int pid, int signal)
{
@ -324,21 +352,21 @@ POSIX_kill(int *errnop, int pid, int sig)
switch(signal){
case PosixSIGKILL:
if(pid > 0)
if(!send_control_msg(pid, "kill")){
if(!__libposix_send_control_msg(pid, "kill")){
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
}
break;
case PosixSIGSTOP:
if(pid > 0)
if(!send_control_msg(pid, "stop")){
if(!__libposix_send_control_msg(pid, "stop")){
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
}
break;
case PosixSIGCONT:
if(pid > 0)
if(!send_control_msg(pid, "start")){
if(!__libposix_send_control_msg(pid, "start")){
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
}
@ -356,6 +384,11 @@ translate_jehanne_note(char *note)
return 0;
}
int
__libposix_note_to_signal(char *note)
{
return atoi(note+__POSIX_SIGNAL_PREFIX_LEN);
}
int
__libposix_note_handler(void *ureg, char *note)
@ -364,7 +397,7 @@ __libposix_note_handler(void *ureg, char *note)
PosixSignalDisposition action;
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
return translate_jehanne_note(note); // TODO: should we translate common notes?
sig = atoi(note+__POSIX_SIGNAL_PREFIX_LEN);
sig = __libposix_note_to_signal(note);
if(sig < __min_known_sig || sig > __max_known_sig)
sysfatal("libposix: '%s' does not carry a signal", note);
*__handling_external_signal = 1;