PDA

View Full Version : [C] Signal (ctrl+z) problemi


Sirbako
17-05-2006, 11:15
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

void ciao(){
printf("ciao\n");
sleep(10);
}

int main(){
pid_t pid1,pid2;
signal (SIGTSTP,ciao);

pid1=fork();
if (!pid1){
printf("gimp\n");
execlp("gimp","gimp",0);
}
else {
pid2=fork();
if (!pid2){
printf("xmms\n");
execlp("xmms","xmms",0);
}else{
printf("stop\n");
sleep(60);
}
}
}

cc
praticamente, se si da CTRL+Z dovrebbe stampare solo "ciao" e non bloccare niente.. invece stampa "ciao" e blocca entrambi i processi.. :muro: :muro: :muro:
dove sta l'inghippo?

andbin
17-05-2006, 11:59
praticamente, se si da CTRL+Z dovrebbe stampare solo "ciao" e non bloccare niente.. invece stampa "ciao" e blocca entrambi i processi..Provo a rispondere io, anche se premetto subito che non sono esperto dei "signal" su sistemi Linux/Unix.

Modificherei il codice così:

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

pid_t pid1,pid2; /* globali */

void ciao(){
printf("ciao\n");
kill (pid1, SIGCONT); /* riavvia figlio 1 */
kill (pid2, SIGCONT); /* riavvia figlio 2 */
sleep(10);
}

int main(){
signal (SIGTSTP,ciao);

pid1=fork();
if (!pid1){
printf("gimp\n");
execlp("gimp","gimp",0);
}
else {
pid2=fork();
if (!pid2){
printf("xmms\n");
execlp("xmms","xmms",0);
}else{
printf("stop\n");
sleep(60);
}
}
}

Quando fai CTRL+Z, sei nel contesto del processo padre. Quando viene eseguito il signal handler in pratica si dovrebbero riavviare i 2 processi figli con il segnale SIGCONT. Io ho provato e sembra funzionare. Ma ripeto ... non sono esperto di 'ste cose. ;)

EDIT: c'è una documentazione dei segnali legati ai job qui (http://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html).

Sirbako
17-05-2006, 18:10
Provo a rispondere io, anche se premetto subito che non sono esperto dei "signal" su sistemi Linux/Unix.

Modificherei il codice così:

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

pid_t pid1,pid2; /* globali */

void ciao(){
printf("ciao\n");
kill (pid1, SIGCONT); /* riavvia figlio 1 */
kill (pid2, SIGCONT); /* riavvia figlio 2 */
sleep(10);
}

int main(){
signal (SIGTSTP,ciao);

pid1=fork();
if (!pid1){
printf("gimp\n");
execlp("gimp","gimp",0);
}
else {
pid2=fork();
if (!pid2){
printf("xmms\n");
execlp("xmms","xmms",0);
}else{
printf("stop\n");
sleep(60);
}
}
}

Quando fai CTRL+Z, sei nel contesto del processo padre. Quando viene eseguito il signal handler in pratica si dovrebbero riavviare i 2 processi figli con il segnale SIGCONT. Io ho provato e sembra funzionare. Ma ripeto ... non sono esperto di 'ste cose. ;)

EDIT: c'è una documentazione dei segnali legati ai job qui (http://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html).
so che così continua, ma a me interessa che non vengano fermati..

andbin
17-05-2006, 21:01
so che così continua, ma a me interessa che non vengano fermati..Se vuoi è possibile fare in modo che la sequenza CTRL+Z venga vista come un tasto qualunque, cioè non come una combinazione "speciale" la cui azione fa andare in background il processo.
Basta mettere all'inizio del programma (nota, includere <termios.h>):
struct termios tios;

if (tcgetattr (1, &tios) == 0)
{
tios.c_cc[VSUSP] = _POSIX_VDISABLE;

if (tcsetattr (1, TCSANOW, &tios) != 0)
printf ("tcsetattr error\n");
}
else
printf ("tcgetattr error\n");In questo modo non è possibile mandare in background il processo usando una combinazione di tasti.

Non so se ti va bene, ovviamente. ;)

Qu@ker
17-05-2006, 22:45
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

void ciao(int unused)
{
write(STDOUT_FILENO, "ciao\n", 5);
}

int main(void)
{
signal(SIGTSTP, ciao);

if (! fork()) {
puts("gimp");
signal(SIGTSTP, SIG_IGN);
execlp("gimp", "gimp", NULL);
_exit(EXIT_FAILURE);
}
if (! fork()) {
puts("xmms");
signal(SIGTSTP, SIG_IGN);
execlp("xmms", "xmms", NULL);
_exit(EXIT_FAILURE);
}
puts("stop");
sleep(60);
puts("done");
wait(NULL);
wait(NULL);
return 0;
}

beppegrillo
17-05-2006, 22:51
La signanl handler dovrebbe avere il seguente prototipo
void func(int signum).
Hai provato a fargli scrivere solo ciao senza fare la sleep? Che cosa ottieni?
Cmq se le tue intenzioni sono quelle di rendere il processo immune dal segnale SIGSTOP puoi fare molto velocemente con
signal(SIGSTP,SIG_IGN);

Sirbako
18-05-2006, 13:21
...


fa in modo che i figli nn si stoppano, però:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
pid_t f1,f2;

void ciao(int unused)
{
kill(f1,SIGTSTP);
printf("ciao %d\n",f1);

}


int main(void)
{
signal(SIGTSTP, ciao);

if (! (f1=fork())) {
puts("gimp");#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

void ciao(int unused)
{
write(STDOUT_FILENO, "ciao\n", 5);
}

int main(void)
{
signal(SIGTSTP, ciao);

if (! fork()) {
puts("gimp");
signal(SIGTSTP, SIG_IGN);
execlp("gimp", "gimp", NULL);
_exit(EXIT_FAILURE);
}
if (! fork()) {
puts("xmms");
signal(SIGTSTP, SIG_IGN);
execlp("xmms", "xmms", NULL);
_exit(EXIT_FAILURE);
}
puts("stop");
sleep(60);
puts("done");
wait(NULL);
wait(NULL);
return 0;
}
signal(SIGTSTP, SIG_IGN);
execlp("gimp", "gimp", NULL);
_exit(EXIT_FAILURE);
}
if (! (f2=fork()) ) {
puts("xmms");
signal(SIGTSTP, SIG_IGN);
execlp("xmms", "xmms", NULL);
_exit(EXIT_FAILURE);
}
puts("stop");
sleep(60);
puts("done");
wait(NULL);
wait(NULL);
return 0;
}


non va, cioè anche se mando il kill non si ferma..
come posso fare?

ilsensine
19-05-2006, 18:17
...
if (! fork()) {
puts("xmms");
signal(SIGTSTP, SIG_IGN);
execlp("xmms", "xmms", NULL);
_exit(EXIT_FAILURE);
}
...

Completamente sbagliato!

Come può una _funzione_ impostata con "signal" essere ereditata dal processo chiamato in exec? Quando chiami la exec, il nuovo processo _sostituisce_ l'immagine in memoria del processo chiamante, comprese le funzioni che gestiscono i segnali.

L'unica cosa che puoi ereditare tramite la exec è la _maschera_ dei segnali; ad esempio puoi impostare SIGTSTP come "mascherato" prima di effettuare le exec:

if (! fork()) {
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGTSTP);
sigprocmask(SIG_BLOCK, &ss, NULL);
execlp(<...>);
_exit(EXIT_FAILURE);
}


In alternativa, se non vuoi mascherare il segnale ma semplicemente evitare che bash invii il segnale anche ai child, creali in una nuova sessione:

if (! fork()) {
setsid();
execlp(<...>);
_exit(EXIT_FAILURE);
}

Sirbako
19-05-2006, 20:31
Completamente sbagliato!

[/code]
:mbe:
a dire il vero se do SIGSTOP invece che SIGNSTP funziona tutto come dovrebbe
il SIGIGN funziona.. prova :mbe:

Sirbako
19-05-2006, 20:38
così funzione (apre 2 gimp, blocca solo il primo, per 10 secondi)

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

pid_t f1,f2;

void ciao()
{
kill(f1,SIGSTOP);
printf("stoppo figlio 1 %d\n");
sleep(10);
kill(f1,SIGCONT);
}


int main(void)
{
signal(SIGTSTP, ciao);
if (! (f1=fork())) {
puts("gimp");
signal(SIGTSTP, SIG_IGN);
execlp("gimp", "gimp", NULL);
_exit(EXIT_FAILURE);
}
else
if (! (f2=fork()) ) {
puts("gimp2");
signal(SIGTSTP, SIG_IGN);
execlp("gimp", "gimp", NULL);
_exit(EXIT_FAILURE);
}
puts("stop");
sleep(60);
puts("done");
wait(NULL);
wait(NULL);
return 0;
}

Qu@ker
19-05-2006, 21:34
Completamente sbagliato!

Come può una _funzione_ impostata con "signal" essere ereditata dal processo chiamato in exec? Quando chiami la exec, il nuovo processo _sostituisce_ l'immagine in memoria del processo chiamante, comprese le funzioni che gestiscono i segnali.


Infatti io non ho impostato una funzione. Ho stabilito di ignorare un certo segnale. E, sono sicuro che la cosa ti stupirà, guarda un po' cosa succede:

goku@big:~$ info libc Processes 'Executing a File' 2>/dev/null |
> sed -ne '136,138p' | cut -d'.' -f1 && echo

Signals that are set to be ignored in the existing process image are
also set to be ignored in the new process image

goku@big:~$

ilsensine
22-05-2006, 08:23
Infatti io non ho impostato una funzione. Ho stabilito di ignorare un certo segnale. E, sono sicuro che la cosa ti stupirà, guarda un po' cosa succede:

Hai ragione, chiedo scusa. SIG_IGN è una direttiva, non un handler particolare, e può essere ereditata.