why pThread exit causes main process termination? - c

I'm testing based on linux 2.6.21 and pThread library.
I tried several cases in order to find out workaround how to avoid main process termination. But, I didn't find out it.
Please, tell me why exiting of thread function causes main process to be terminated?
Here is test code below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <linux/input.h>
#include <fcntl.h>
#include <errno.h>
#include <dlfcn.h>
#include <time.h>
#include <pthread.h>
int handle = 0;
int main_loop = 0;
void *testThread(void *pParm)
{
int i;
for (i=0; i < 5 ; i++){
printf("====testThread loop %d\n", i);
sleep(1);
}
if (main_loop == 1){
exit(0);
}
else if (main_loop == 2)
{
sleep(10);
exit(0);
}
else if (main_loop == 3)
{
pthread_exit(NULL);
}
else if (main_loop == 4)
{
sleep(10);
pthread_exit(NULL);
}
}
int main(int argc, char *argv[])
{
pthread_t pTestThread;
int i, ret;
if (argc == 2){
main_loop = atoi(argv[1]);
}
if (argc == 3){
main_loop = atoi(argv[1]);
handle = atoi(argv[2]);
}
ret = pthread_create(&pTestThread, NULL, (void *)testThread, NULL);
if (0 == ret){
if (handle == 0)
pthread_detach(pTestThread);
printf("====Thread creation okay!\n");
}else{
printf("====Thread creation error!\n");
return 0;
}
if (handle == 1)
{
printf("====pthread_join waiting\n");
pthread_join(pTestThread, (void **)&ret);
printf("====pthread_join ret %d\n", ret);
}
for (i=0; i < 20; i++)
{
printf("====Main loop %d\n", i);
sleep(1);
}
printf("====Main Exit\n");
return 0;
}
In this code, I have never seen the log of "====Main Exit" with a various combinations (argument 2nd and 3rd).

. Please, tell me why exiting of thread function causes main process
to be terminated?
Yes, In your thread function, you use "exit()", This function can "Terminates the process normally, performing the regular cleanup for terminating programs."
you can see http://www.cplusplus.com/reference/cstdlib/exit/ for more details:
Calling this function destroys all objects with static duration: A
program with multiple threads running shall not call exit (see
quick_exit for a similar function that does not affect static
objects).
So if you use pthread_exit instead of exit, you can see
====Main loop 18
====Main loop 19
====Main Exit
By the way,
ret = pthread_create(&pTestThread, NULL, (void *)testThread, NULL);
should be
ret = pthread_create(&pTestThread, NULL, testThread, NULL);

Looking at your code, ( assuming main_loop and handle are global )
if (main_loop == 1){ // Main thread will exit for if 1st argument is 1
exit(0);
}
else if (main_loop == 2) // Main thread will exit for if 1st argument is 2
{
sleep(10);
exit(0);
}
else if (main_loop == 3) // Main thread should not exit if 3
{
pthread_exit(NULL);
}
else if (main_loop == 4)
{
// Main thread should not exit if 3, delay however is 10 seconds
sleep(10);
pthread_exit(NULL);
}
// Interestingly for all other values main should run as usual
try running your binary as
./a.out 3 1
./a.out 4 1
./a.out 123 1
Note - 2nd argument is always 1, for execution to be sequenced.

Related

C Thread doesn't run in linux terminal

My program has to increment a counter strictly alternatively using 2 threads and synchronizing them using a pipe file. I know it doesn't really make sense but it's a university task. The problem works if I run it with CodeBlocks for instance but it doesn't print anything when I execute the program from linux terminal and I can't figure out why. Any idea?
Here is my code:
#include <stdlib.h>
#include <pthread.h>
#include <wait.h>
#include <unistd.h>
#include <string.h>
int contor;
int fd[2];
void* thread_function(void* arg) {
int* th = (int*)arg;
char x = 'x';
while(1)
{
if (*th == 0 && contor % 2 == 0 && contor < 100) {
close(fd[0]);
write(fd[1], &x, 1);
contor++;
printf("Counter: %d incremented by thread: %ld\n", contor, pthread_self());
sleep(0);
if (contor >= 100)
{
pthread_exit(NULL);
}
} else if (*th == 1 && contor % 2 == 1 && contor < 100){
close(fd[1]);
read(fd[0], &x, 1);
contor++;
printf("Counter: %d incremented by thread: %ld\n", contor, pthread_self());
if (contor >= 100)
{
pthread_exit(NULL);
}
}
if (contor >= 100)
{
pthread_exit(NULL);
}
}
}
void main(int argc, char** argv) {
int tr1 = 0;
int tr2 = 0;
pthread_t t1, t2;
int th0 = 0;
pipe(fd);
tr1 = pthread_create(&t1, NULL, &thread_function, (void*)&th0);
if (tr1) {
printf("Error creating thread #1!");
}
int th1 = 1;
tr2 = pthread_create(&t2, NULL, &thread_function, (void*)&th1);
if (tr2) {
printf("Error creating thread #2!");
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}
I compile the file using: gcc -o ex.exe ex.c -lpthread
I execute the executable using: ./ex.exe
File descriptors are shared by all the threads of a process. One of your threads is closing one end of the pipe (fd[0]) and writing the other end of the pipe (fd[1]). Your other thread is closing the other end of the pipe (fd[1]) and reading the other end of the pipe (fd[0]). Also, they are being closed multiple times in a while loop.
Getting rid of the close(fd[0]) and close(fd[1]) calls in thread_function will help a bit. There may be other problems in thread_function because the program stopped producing output after the counter reached the value 3 when I tried it.
Hint: Use two pipes.

Linux syscalls: PTRACE_O_TRACECLONE causes indefinite hanging

I have a binary from which I need to intercept a certain syscall--in this case unlinkat--and make it do nothing. I have the following code which works fine for a single process; however, with PTRACE_O_TRACECLONE added to the ptrace opts, after the tracee makes a call to clone, the waitpid call hangs forever. I've been pulling my hair out for days on different parts of the internet, to the point where I was going through the source of strace, and had in fact straced strace to see what the strace I had straced was ptracing.
Here's the source--I removed some stuff to make it as minimal as possible for readability.
#define _POSIX_C_SOURCE 200112L
// std (i think)
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// linux
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#define OPTS PTRACE_O_TRACESYSGOOD // | PTRACE_O_TRACECLONE | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEFORK
#define WOPTS 0
/* The TRACEE. Executes the process we want to target with PTRACE_TRACEME */
int do_child(int argc, char **argv) {
char *args[argc + 1];
memcpy(args, argv, argc * sizeof(char *));
args[argc] = NULL;
ptrace(PTRACE_TRACEME);
kill(getpid(), SIGSTOP);
return execvp(args[0], args);
}
/* Waits for the next syscall and checks to see if the process has been exited */
int wait_for_syscall(pid_t child) {
int status;
while (1) {
ptrace(PTRACE_SYSCALL, child, 0, 0);
waitpid(child, &status, WOPTS); // <--- THIS CALL HANGS FOREVER AFTER CLONE
if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80)
return 0;
if (WIFEXITED(status))
return 1;
}
return -1; // unreachable
}
/* The TRACER. Takes the pid of the child process that we just started and actually does the
PTRACE stuff by passing signals back and forth to that process. */
int do_trace(pid_t child) {
int status, syscall;
waitpid(child, &status, WOPTS);
ptrace(PTRACE_SETOPTIONS, child, 0, (unsigned long)OPTS);
while (1) {
// ptrace(PTRACE_SYSCALL) really needs to be called twice, first is before entry second is after exit, but idgaf
if (wait_for_syscall(child) != 0) {
break;
}
syscall = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_RAX);
switch (syscall) {
case SYS_clone:
fprintf(stderr, "DEBUG: clone detected\n");
break;
case SYS_unlinkat:
fprintf(stderr, "DEBUG: unlinkat detected\n");
ptrace(PTRACE_POKEUSER, child, sizeof(long) * RAX, 0);
break;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s prog args\n", argv[0]);
exit(1);
}
pid_t child = fork();
if (child == 0) {
return do_child(argc - 1, argv + 1);
} else {
return do_trace(child);
}
return 0;
}
Just as a disclaimer, I am NOT a C developer, these days I mainly write Python, so a lot of this was just copied and pasted from different tutorials I found and I basically added/removed random shit until gcc didn't give me that many warnings.
Based on what I've read, I suspect the issue is something about raising signals to the processes involved and waiting for a SIGTRAP, I just have no real intuition on what to do at that level.
The solution was using libseccomp instead.
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <seccomp.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
int do_child(int argc, char **argv)
{
char *args[argc + 1];
memcpy(args, argv, argc * sizeof(char *));
args[argc] = NULL;
return execvp(args[0], args);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s prog args\n", argv[0]);
exit(1);
}
// Init the filter
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW); // default allow
// setup basic whitelist
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(0), SCMP_SYS(unlinkat), 0);
// build and load the filter
seccomp_load(ctx);
pid_t child = fork();
if (child == 0)
{
return do_child(argc - 1, argv + 1);
}
return 0;
}

Ptrace or waitpid gets stuck in C on macOS

I'd like to write a mini-debugger with ptrace on OS X.
I want the parent process to make the child process run step by step.
This is what I tried, but the program gets stuck sometimes, it seems to be in an infinite loop or to be frozen.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/user.h>
#include <sys/types.h>
#include <sys/ptrace.h>
int main(void)
{
pid_t id = fork();
if (id < 0)
return 1;
else if (id == 0)
{
ptrace(PT_TRACE_ME, 0, 0, 0);
printf("Point 1\n");
kill(getpid(), SIGSTOP);
printf("Point 2\n");
exit(1);
}
else
{
while (1)
{
int status = 0;
pid_t retpid = waitpid(id, &status, WUNTRACED);
if (retpid < 0)
{
printf("Waitpid error\n");
exit(3);
}
if (WIFSTOPPED(status))
{
int ret = ptrace(PT_STEP, id, (caddr_t)1, 0);
if (ret < 0)
{
printf("Ptrace error\n");
exit(2);
}
}
else
{
printf("Program has terminated\n");
exit(0);
}
}
}
}
Compile with cc bug.c, run with while true; do ./a.out; done, wait 30 seconds and it will freeze.
When it freezes, the last lines are:
Point 1
Point 2
I can't figure out what I'm doing wrong.
Running on macOS Sierra 10.12.6 with Apple LLVM version 8.1.0 (clang-802.0.42)

waitpid() not waiting for child

I wrote a really basic shell and for some reason, when I use fork() and then waitpid() the parent process won't wait for the child.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
#include "LineParser.h"
#include <termios.h>
#define MAX_STR 2048
void execute(cmdLine *pCmdLine);
int main()
{
char isContinuing = 1;
char path[PATH_MAX];
char str[MAX_STR];
char something[MAX_STR+PATH_MAX];
cmdLine* cmd;
while(isContinuing)
{
getcwd(path, PATH_MAX);
printf("%s$ ", path);
fgets(str, MAX_STR, stdin);
if(!strncmp(str, "quit", strlen("quit")))
{
isContinuing = 0;
}
else
{
cmd = parseCmdLines(str);
if(cmd->arguments != '\0')
{
execute(cmd);
}
}
}
freeCmdLines(cmd);
return 0;
}
void execute(cmdLine *pCmdLine)
{
pid_t id = fork();
if(id == 0)
{
printf("I AM CHILD.\n");
if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
{
perror("execvp failed.\n");
exit(1);
}
exit(0);
}
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id);
printf("DONE WAITING\n");
}
LineParser header file is mine and it is fully working.
Now, for some reason, only the first command is working as expected,
let's assume an input "echo hi", the output is:
I AM PARENT.
WAITING FOR CHILD.
I AM CHILD.
DONE WAITING.
as expected and then it prints "hi" and the path, waiting for a command again.
For some reason, when I enter the SAME input "echo hi" the second time, the output is:
I AM PARENT.
WAITING FOR CHILD.
DONE WAITING.
$PATH$ //(WITHOUT WAITING FOR INPUT !!!)
I AM CHILD.
hi
//and here waiting for input//
Why does this happen?
There are several problems with your code:
not clearing malloc'd memory on every iteration through the while loop
putting a exit() statement in unreachable code
incorrect parameter list for the waitpid() function
unclear delination between parent code and child code in execute function
unused variable something
failed to check return value from fgets function
missing #include for sys/types.h
missing #include for sys/wait.h
IMO: the question should have included the definition of struct cmdLine
So here is a compilable version of your code. The compiler found many problems with the original code.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/limits.h>
//#include "LineParser.h"
#include <termios.h>
#include <sys/types.h>
#include <sys/wait.h> // prototype for waitpid()
//note: pid_t waitpid(pid_t pid, int *status, int options);
struct cmdLine
{
char ** arguments; // arguments[x] = ptr to an argument string
};
#define MAX_STR (2048)
#define MAX_PATH (256)
void execute(struct cmdLine *);
struct cmdLine * parseCmdLines( char * );
void freeCmdLines( struct cmdLine * );
int main()
{
char path[PATH_MAX];
char str[MAX_STR];
//char something[MAX_STR+PATH_MAX];
struct cmdLine* pCmd = NULL;
while(1)
{
getcwd(path, PATH_MAX);
printf("%s$ ", path);
if( NULL == fgets(str, MAX_STR, stdin) )
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// implied else
if(!strncmp(str, "quit", strlen("quit")))
{ // then strings equal
break; // exit while loop (and pgm)
}
// implied else input not equal 'quit'
pCmd = parseCmdLines(str);
if( (NULL != pCmd) && (NULL != pCmd->arguments) )
{ // then one or more arguments entered/parsed
execute(pCmd);
} // end if
freeCmdLines(pCmd); // free all strings memory, then free struct memory
pCmd = NULL; // cleanup
} // end while
return 0;
} // end function: main
void execute(struct cmdLine *pCmdLine)
{
int status = 0;
pid_t id = fork();
if(id == 0)
{ // then, child
printf("I AM CHILD.\n");
if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments))
{ // if no error then never gets here
perror("execvp failed.\n");
} // end if
}
else
{ // else, parent
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id, &status, 0);
printf("DONE WAITING\n");
} // end if
} // end function: execute
You invoke undefined behavior by calling the waitpid() function with the wrong number of arguments. Anything could happen.
This simplified variant of your code works fine for me:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main ()
{
int i;
for (i = 0; i < 3; i += 1)
{
pid_t id = fork();
if(id == 0)
{
char *argv[] = { "echo", "hi", NULL };
printf("I AM CHILD.\n");
execvp("echo", argv);
/* failed to exec */
perror("execvp failed.\n");
exit(1);
} else if (id < 0) {
perror("fork failed.\n");
exit(1);
}
printf("I AM PARENT.\n");
printf("WAITING FOR CHILD.\n");
waitpid(id, NULL, 0);
printf("DONE WAITING\n");
}
return 0;
}
Your call to waitpid(2) is wrong.
According to man 2 waitpid, it's:
pid_t waitpid(pid_t pid, int *status, int options);
You probably need to define an int and call it as:
waitpid(id, &status, 0);
or use the simpler version wait(2), which will work for any child:
wait(&status);
Your main problem is that you don’t let the compiler check your code. You should generally enable the compiler warnings and try to understand them.
$ gcc -Wall -Wextra -Werror -Os -c myshell.c
This is the minimum command line I use. When your code compiles with these settings, you have already eliminated a bunch of hard-to-find bugs in your code. Among these bugs is, as others already have mentioned, the call to waitpid.
Have a look at http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html. The Open Group specification requires that you #include the two headers <sys/types.h> and <sys/wait.h> before using the waitpid function. Your program doesn’t do this.

Wait for a Forked Process when using a Semaphore

I'm trying to code an exercise in C Linux where I have one semaphore with 2 spots and "n" processes entered by argument. I need that the first 2 processes use the semaphore using the 2 spots for 5 secs each and then leave the semaphore for the other remaining processes to do their stuff. The problem is that not all the other processes wait for the semaphore to be free and some of them show a semaphore error (look at the results at the bottom). I believe the problem is on the waits for the child processes, because I have a waitipid and a wait function, but I need that if there's a free spot in the semaphore, any child process running could use it. Here's the code:
//gcc SemaphoreExample.c -o s
//./s 5
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
void semaphoreTask(int semid, int semnum, int semBusy)
{
struct sembuf data;
data.sem_num = semnum;
data.sem_flg = 0;
data.sem_op = semBusy;
if(semop(semid,&data,1) == -1)
{
printf("\nSemaphore Error\n");
exit(-1);
}
}
int main(int argc, char *argv[])
{
int i, fdSemaphore, quantity, fdsemctl, j;
pid_t pid[15];
system("clear");
if(argc-1 < 1)
{
printf("Some arguments are missing\n");
return EXIT_FAILURE;
}
printf("Number of arguments entered:\n\nargc: %d\n\nValues from the arguments:\n\n",argc-1);
for(i=0;i<argc;i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
printf("\n\n");
fdSemaphore = semget(1234,1,IPC_CREAT|0777);
if(fdSemaphore == -1)
{
printf("\nError creating the Semaphore\n");
return EXIT_FAILURE;
}
fdsemctl = semctl(fdSemaphore,0,SETVAL,2);
if(fdsemctl == -1)
{
printf("\nError opening the Semaphore\n");
return EXIT_FAILURE;
}
quantity = atoi(argv[1]);
for(i=0;i<quantity;i++)
{
pid[i] = fork();
if(pid[i] == -1)
{
printf("\nError creating the Child Process\n");
return EXIT_FAILURE;
}
if(pid[i] == 0)
{
semaphoreTask(fdSemaphore,0,-1);
printf("\n[%d] I go to sleep\n",getpid());
sleep(5);
printf("\n[%d] I wake up\n",getpid());
semaphoreTask(fdSemaphore,0,1);
}
else
{
//printf("\nJust wait\n");
waitpid(pid[i],NULL,WNOHANG);
}
}
for(j=0;j<quantity;j++)
{
wait(NULL);
}
semctl(fdSemaphore,0,IPC_RMID);
return EXIT_SUCCESS;
}
This is the result I got:
Result:
Number of arguments entered:
argc: 1
Values from the arguments:
argv[0]: ./s
argv[1]: 5
[2845] I go to sleep
[2844] I go to sleep
[2845] I wake up
[2844] I wake up
Semaphore Error
[2843] I go to sleep
Semaphore Error
Semaphore Error
[2843] I wake up
Semaphore Error
Should I use wait or waitpid only?
The problem is semaphores are getting removed by forked children.
After line
semaphoreTask(fdSemaphore,0,1);
add
exit(0);
It is much simpler to implement what you want if you use sem_post and sem_wait calls. I am on a OpenBSD system and I am assuming that Linux has the same thing.

Resources