PDA

View Full Version : How correctly continue paused process?



icegood
12-04-2010, 02:28 PM
I have child process that paused. How better to continue it? At first glance better to send SIGCONT because by documentation pause returns after EVERY signal but...


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>

int iceu_signals_init_signal_handler(const sigset_t ........et, __sighandler_t/*__sighandler_t*/ sgnhnd)
{
static struct sigaction sa_act;
int i;
//
memset(&sa_act, 0, sizeof(sa_act));
sa_act.sa_handler=sgnhnd;
// blocking all signals while handler occurs:
if (sigfillset(&(sa_act.sa_mask)))
{
fprintf(stderr, "Cannot fill set of all signals\n");
return 1;
}
for (i=1; i<=_SIGSET_NWORDS; i++)
{
switch (sigismember(sset, i))
{
case 1:
if(sigaction(i, &sa_act, NULL))
{
fprintf(stderr, "Cannot set signal %i(%s)\n", i, sys_siglist[i]);
return 10*i;
}
break;
case 0:
continue;
case -1:
{
fprintf(stderr, "Cannot check signal membership: %i(%s)\n", i, sys_siglist[i]);
return 5;
}
}
}
return 0;
}

int iceu_signals_set_signals(sigset_t ........et, const int *set, int cnt)
{
int i;
//
if (sigemptyset(sset))
{
fprintf(stderr, "Cannot do empty set of signals\n");
return 1;
}
for (i=0;i<cnt;i++)
{
if (sigaddset(sset, set[i]))
{
fprintf(stderr, "Cannot add to set signal %i(%s)\n", set[i], sys_siglist[set[i]]);
return set[i]*100+1;
}
}
return 0;
}

static void ProcessSigHandler(int sg)
{
if (sg==SIGSTOP)
fprintf(stderr, "Process stopped\n");
}

int main()
{
//1) register signals
static sigset_t sset;
int s=SIGSTOP;
//
if (iceu_signals_set_signals(&sset, &s, 1))
return 1;
iceu_signals_init_signal_handler(&sset, &ProcessSigHandler);
fprintf(stderr, "Process started\n");
pause();
//kill(getpid(), SIGSTOP);
kill(getpid(), SIGCONT);
fprintf(stderr, "Process is about to terminate\n");
return 0;
}

Simple test. Runned, after pausing i begin to send signals from other terminal. After this works everything but... CONT! Even SIGUSR1 works! What's going on? Why actually pause hasn't same behaivor as kill(getpid(), SIGSTOP)?

---------
istead of ........ should be "*\ss" in code. Admins, do smth with editor, please

Salem
12-04-2010, 04:36 PM
Basic test.


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void h_sigstop ( int sig ) {
printf("Never happens (%d)\n",sig);
}
void h_sigcont ( int sig ) {
printf("Huh? what? (%d)\n",sig);
}

int main( void )
{
int i;
printf("Running as PID=%d\n",getpid());
signal(SIGCONT,h_sigcont);
signal(SIGSTOP,h_sigstop);
for ( i = 0 ; i < 10 ; i++ ) {
printf("Loop=%d\n",i);
if ( i == 5 ) kill(getpid(),SIGSTOP);
sleep(2);
}
return 0;
}




$ ./a.out &
[2] 5380
$ Running as PID=5380
Loop=0
Loop=1
Loop=2
Loop=3
Loop=4
Loop=5


[2]+ Stopped ./a.out
$ a=$!
$ kill -s CONT $a
Huh? what? (18)
$ Loop=6
Loop=7
Loop=8
Loop=9

[2]+ Done ./a.out

It forces itself to take a nap, and then I wake it up.
Is this what you're trying to do?

icegood
12-05-2010, 07:59 AM
Almost that. I mean i want to do same via pair (pause(), kill(child_pid,SIGCONT)) instead of
( kill(my_pid,SIGSTOP), kill(child_pid,SIGCONT)).
First procedure always called in child, second - in parent.
Because i don't know how program will behave after sending itself SIGSTOP. Will it do smth before it really stops? You do for that sleep(2) just to clear signals queue. If it would be enough i will happy.
Otherwise i should work via pair (pause(), kill(child_pid,SIGUSR1))

icegood
12-05-2010, 08:04 AM
And yes, SIGSTOP hasn't handler. Maybe it means that it doesn't even go via signals queue and do that more directly. Then, of course, we don't need sleep(2). Everything wil be fine.

Salem
12-05-2010, 08:30 AM
Sending SIGSTOP to yourself is "do not pass go, do not collect $200" territory.

What about
kill(child,SIGCONT); kill(self,SIGSTOP);

and
kill(parent,SIGCONT); kill(self,SIGSTOP);

if you want them to alternate in some way?

icegood
12-05-2010, 09:43 AM
Sending SIGSTOP to yourself is "do not pass go, do not collect $200" territory.

:) Nothing understood but sounds good :)


What about
kill(child,SIGCONT); kill(self,SIGSTOP);

and
kill(parent,SIGCONT); kill(self,SIGSTOP);

if you want them to alternate in some way?
Much more nicer then i've implemented.
I continued parent process via

do
{
waitpid(child_pid_or_zero_for_parent, &status, WUNTRACED);
} while (!WIFSTOPPED(status));

it means that child should stop itself via SIGSTOP itself. But your solution much more clearer because it doesn't understood at all how child will change it state via sytem() calling in itself. So i need this loop :(

icegood
12-06-2010, 02:47 PM
Of course, nothing works... :(
Not so simple as it use to be... The reason is, for example, when i run kill(parent,SIGCONT); from child process that child should firstly return from kill otherwise uncontrollable execution of parent leads to "Interruptable system call" in some other system call. I.e. signal-safe kill() doesn't mean interprocess-glibc-safety. So, question remains same

Salem
12-06-2010, 03:02 PM
Perhaps you need a proper semaphore / mutex between them?

icegood
12-06-2010, 05:44 PM
Need! But how?

icegood
12-06-2010, 08:22 PM
WTF? Defenetly smth else happens! I inserted true thread-safe code in child process


while(1)
{
for(i=0;i<arrsize(buf_i);i++)
buf_i[i]=i;
}


And child hangs inside this loop (i see that under debugger that i've attached to child)
After that i try to continue parent and nothing good happens. Interrupted system call inside strtoll() somewhere in other place of world.
Full code is:


#include "ice_system.h"
#include <stdio.h>
#include <unistd.h>

#ifdef ice_system_call_light_weight_shell_task_imlemented
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
static FILE *exec_file=NULL;
static const char *FileName="./ice_system_shell_task.sh";
static pid_t child_pid_or_zero_for_parent, parent_id;
static int EndChildProcess, ProcessContinued;
static char buf[256];

static int SendSignalToProcess(pid_t p_id, int sig_id)
{
if (kill(p_id, sig_id)==-1)
{
perror("SendSignalToProcess");
fprintf(stderr, "There was troubles trying to send signal %d to process %d\n", sig_id, p_id);
return 1;
}
return 0;
}

static inline void DoProceedChildProcess()
{
#ifdef debug
fprintf(stderr, "Task from file %s is about to proceed\n", FileName);
#endif
if (system(FileName)==-1)
perror("DoProceedChildProcess");
#ifdef debug
fprintf(stderr, "Task from file %s done\n", FileName);
#endif
}

static inline void ChildProcessSigHandler(int sg)
{
if (sg==SIGUSR1)
DoProceedChildProcess();
else //SIGTERM
EndChildProcess=1;
}

static inline void ParentProcessSigHandler(int sg)
{
ProcessContinued=1;
}

static inline int InitChildProcess()
{
//1) register signals
static sigset_t sset;
int v_signals[]={SIGTERM, SIGUSR1};
//
if (iceu_signals_set_signals(&sset, v_signals, arrsize(v_signals)))
return 1;
iceu_signals_init_signal_handler(&sset, &ChildProcessSigHandler);
return 0;
}

static inline void RunChildProcess()
{
int buf_i[1024], i;
//
while(!EndChildProcess)
{
while(1)
{
for(i=0;i<arrsize(buf_i);i++)
buf_i[i]=i;
}
pause();
SendSignalToProcess(parent_id, SIGUSR1); // child just waits until will not ended
}
snprintf(buf, sizeof(buf), "rm -f %s", FileName);
if (system(buf)==-1)
perror("ice_system_call_light_weight_shell_task_free. system:");
exit(0);
}

static inline int InitParentHandler()
{
static sigset_t sset;
int v_signals[]={SIGUSR1};
//
if (iceu_signals_set_signals(&sset, v_signals, arrsize(v_signals)))
return 1;
iceu_signals_init_signal_handler(&sset, &ParentProcessSigHandler);
return 0;
}

int ice_system_call_light_weight_shell_task_init()
{
// 1)
if ((exec_file=iceu_system_safely_open_file(FileName, "w"))==NULL)
return 1;
fclose(exec_file);
sprintf(buf, "chmod u+x %s", FileName);
if (system(buf)==-1)
return 1;
if (InitParentHandler())
return 1;
ProcessContinued=0; // actually for parent
switch (child_pid_or_zero_for_parent=fork())
{
case -1: // with errors will be in main window
{
perror("fork");
return 1;
}
case 0: // child process
{
if (InitChildProcess())
exit(0);
parent_id=getppid();
EndChildProcess=0;
SendSignalToProcess(parent_id, SIGUSR1); // child just waits until will not ended
RunChildProcess();
}
default: // parent process
{
while(!ProcessContinued)
sleep(2); // wait for initialization of child
#ifdef debug
fprintf(stderr, "Parent id is %d\n", getpid());
fprintf(stderr, "Child id is %d\n", child_pid_or_zero_for_parent);
#endif
}
}
return 0;
}

void ice_system_call_light_weight_shell_task_free()
{
pid_t pid;
int status;
//
if (child_pid_or_zero_for_parent!=-1)
{
SendSignalToProcess(child_pid_or_zero_for_parent, SIGTERM);
// now wait until it really exited:
while(((pid=waitpid(child_pid_or_zero_for_parent, &status, 0))!=child_pid_or_zero_for_parent)||
(!WIFEXITED(status)))
{
if(pid<=0)
{
fprintf(stderr, "Error occured trying to end child\n");
break;
}
}
}
}
#endif //ice_system_call_light_weight_shell_task_imlemented

// dislike to system() call this one is lightweighted provided there is no fork call so there is no memory consumption
int ice_system_call_light_weight_shell_task(const char *task)
{
#ifndef ice_system_call_light_weight_shell_task_imlemented
if (system(task)==-1)
{
perror("ice_system_call_light_weight_shell_task");
return 1;
}
#else
if ((exec_file=iceu_system_safely_open_file(FileName, "w"))==NULL)
return 1;
fprintf(exec_file, "#!/bin/bash\n%s\nexit 0", task);
fclose(exec_file);
ProcessContinued=0;
#ifdef debug
fprintf(stderr, "Task \"%s\" is about to proceed\n", task);
#endif
if (SendSignalToProcess(child_pid_or_zero_for_parent, SIGUSR1))
return 1;
while(!ProcessContinued)
sleep(1);
/*
if (SendSignalToProcess(parent_id, SIGSTOP))
return 1;
*/
#endif
return 0;
}


I don't get it! WTF? Maybe after fork child and parent had smth common that shouldn't be common anymore?