Understanding the code in C involving processes - c

Someone can explain me why the first code the variable "v" dont change the value in the last prinft() and se second code the variable "v" change.
First code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int v = 5;
int main(){
pid_t piid;
piid = fork();
if(piid==0){
v += 15;
return 0;
}
else if(piid >0){
wait(NULL);
printf("Final value = %d\n",v);
return 0;
}
}
I know this code be involving fork() for create another process maybe
Second code:
#define _GNU_SOURCE
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sched.h>
#include <stdio.h>
// 64kB stack
#define FIBER_STACK 1024*64
int v = 5;
int threadFunction( void* argument )
{
v += 10;
return 0;
}
int main(){
void* stack;
pid_t pid;
stack = malloc( FIBER_STACK );
if ( stack == 0 )
{
perror("malloc: could not allocate stack\n");
exit(1);
}
pid = clone( &threadFunction, (char*) stack + FIBER_STACK,
SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, 0 );
if ( pid == -1 )
{
perror( "clone" );
exit(2);
}
pid = waitpid( pid, 0, 0 );
if ( pid == -1 )
{
perror( "waitpid" );
exit(3);
}
free( stack );
printf("Final value = %d\n", v);
return 0;
}
This code is a thread, but I can not understand the so-called clone () and what's inside there.

Forking a new process creates a standalone and distinct copy of the original process. Changing something in the process copy will not change anything in the original process.
Threads are different, they share everything. All threads are still parts of the same process.
While the clone system call can create a new process (that's what happens when you call fork in Linux actually) it can also be used to create a thread, which is what happens in the second program.

threads run in a shared memory space, while processes run in separate memory spaces.
so in the first case using fork each process has different reference of the variable v while in the thread both has the same reference.

Related

The GNU's clone() function got stuck

I am writing a program using Code::Blocks 16.01 in CentOS 7.3. The program is contains the main function and a child process (or so-called thread) created by the clone() function. My purpose is to test whether the chdir() function affects the working directory in the main function by removing the CLONE_FS parameter. Hopefully it works, but new problem occurs. Please read my code first:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sched.h>
#include <fcntl.h>
#define STACK_SIZE 1024*1024*8
int thread_func(void *arg){
int i;
char *cdir;
for(i = 0; i < 100; i++){
switch(i%3){
case 0:
chdir("/home/centos/dirtest/dir000");
break;
case 1:
chdir("/home/centos/dirtest/dir001");
break;
case 2:
chdir("/home/centos/dirtest/dir002");
break;
}
cdir = getcwd(NULL,0);
fprintf(stderr,"Child Thread in # %d: %s\n",i,cdir);
}
free(cdir);
return 1;
}
int main(){
void *pstack = (void*)mmap(NULL, STACK_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON,
-1, 0);
if(MAP_FAILED != pstack){
int ret,i;
char *cdir;
ret = clone(thread_func,
(void*)((unsigned char *)pstack + STACK_SIZE),
CLONE_VM | CLONE_FILES ,
NULL);
if(ret == -1){
fprintf(stderr,"Thread create failed\n");
return 0;
}
for(i = 0; i < 100; i++){
cdir = getcwd(NULL,0);
fprintf(stderr,"Main Function in # %d: %s\n",i,cdir);
}
free(cdir);
}
return 1;
}
However, when I run the generated exe file in the terminal by command line, it got stuck. Neither the main function nor the child process could finish its "for" loop, and I had to terminate the program by "Ctrl-C".
Could anybody find the problem ?
********Here are edits of new progress********
Thanks for the comments, I've made changes on the getcwd() function. Also I added the waitpid() function. However, it shows failure. The modified code is as follows:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sched.h>
#include <fcntl.h>
#define STACK_SIZE 1024*1024*8
int thread_func(void *arg){
int i;
char cdir[1024];
for(i = 0; i < 100; i++){
switch(i%3){
case 0:
chdir("/home/centos/dirtest/dir000");
break;
case 1:
chdir("/home/centos/dirtest/dir001");
break;
case 2:
chdir("/home/centos/dirtest/dir002");
break;
}
getcwd(cdir,sizeof(cdir));
fprintf(stderr,"Child Thread in # %d: %s\n",i,cdir);
}
return 1;
}
int main(){
/*void *pstack = (void*)mmap(NULL, STACK_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS ,
-1, 0);
if(MAP_FAILED != pstack){*/
void *pstack = malloc(STACK_SIZE);
int ret,i;
char cdir[1024];
ret = clone(thread_func,
(void*)((char *)pstack + STACK_SIZE),
CLONE_VM | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD,
NULL);
if(ret == -1){
fprintf(stderr,"Thread create failed\n");
goto mem;
}
for(i = 0; i < 100; i++){
getcwd(cdir,sizeof(cdir));
fprintf(stderr,"Main Function in # %d: %s\n",i,cdir);
}
ret = waitpid(ret,0,0);
if(ret == -1){
fprintf(stderr,"waitpid failed\n");
}
mem:
//}
free(pstack);
return 1;
}
I'm quite certain that one of the problems is that you have multiple threads of execution touching libc without actually preparing libc for it. When threads are spawned normally, with pthreads, they run some code that prepares libc for multiple threads touching stdio (you print to stderr), enable locking for malloc (since you do mallocs inside getcwd), set up TLS and generally make sure that things don't run into each other.
You've done none of that. You're of course free to spawn your own threads with clone manually, but then it's your responsibility to make sure that all the code you call is thread safe. You can't just call into libc and hope for the best, that won't work. Libc expects that either there is just one thread executing or that the threads were created with pthreads.

Thread not hitting thread function every time

I am trying to make a program that takes several files, appends them all into one big file. Each append has to be done by a separate thread.
/*
This program creates appends several files together
*/
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
pthread_t *tids;
void *threadout(void *num);
int main(int argc, char *argv[])
{
int numOfFiles = atoi(argv[2]);
int error;
int index;
sem_t sem;
//Used for output file
int outFile;
//Checking to make sure there is the correct number of arguments
if (argc != 4)
{
printf("%s \n", "Wrong number of arguments, exiting program.");
return 1;
}
//checking to make sure there are at least two files to append
if (numOfFiles < 2)
{
printf("%s \n", "Cannot append 1 file or less.");
return 1;
}
//opening/creating file
outFile = open(argv[3], O_WRONLY | O_CREAT, S_IRUSR);
///****************** Allocate space for thread ids ******************/
tids = (pthread_t *)calloc(numOfFiles, sizeof(pthread_t));
if (tids == NULL)
{
perror("Failed to allocate memory for thread IDs");
return 1;
}
if (sem_init(&sem, 0, 1) == -1)
{
perror("Failed to initialize semaphore");
return 1;
}
/****************** Create threads *********************************/
for (index = 0; index < numOfFiles; index++)
{
if (error = pthread_create(tids + index, NULL, threadout, &index))
{
fprintf(stderr, "Failed to create thread:%s\n", strerror(error));
return 1;
}
}
return 0;
}
void * threadout(void *num)
{
printf("Hello");
return NULL;
}
Near the bottom of the program I do the actual creating of the threads. The first thing the thread should do is hit the "threadout" function. However the only way I can get anything to print is if I say to create a large number of threads. So if I tell my program to create 5000 threads, "Hello" will be printed. Not 5000 times though. If I asked it to create 10 threads nothing is printed. Am I doing something wrong when I invoke "threadout"? Thanks
Returning from main causes your entire program to exit, even if other threads are running.
Your main function exits when all threads are started. If you're starting lots of threads, this leaves enough time for the first ones to print. If you're starting few threads, it returns before the first ones get to print anything.
You might want to use pthread_join (called once per thread) to wait for all threads to terminate.

Child process not continuing execution when ptrace'ing

I made the following simple example to read memory from a child process using ptrace.
I want to see the value at a specific address, 0x601050, every second during the execution of a small matrix multiplication program. I use PTRACE_PEEKDATA followed by PTRACE_CONT and sleep for 1 second, in an infinite loop, to do so.
However, the matrix multiplication program never proceeds--it should print to stdout in the first instruction, but it never seems to execute. I understood that ptrace(PTRACE_CONT,pid) would signal the child to resume execution and that sleep(1) would allow it to execute for a second (until the next ptrace call), but that is not the case.
#include <string.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/reg.h>
int read_mem(long *out, pid_t pid, long addr, size_t sz)
{
long tmp;
size_t copied = 0;
while(copied < sz)
{
tmp = ptrace(PTRACE_PEEKDATA, pid, addr+copied);
if(errno)
{
fprintf(stderr,"ptrace: error : %s\n",strerror(errno));
return copied;
}
memcpy(out,&tmp,sizeof(long));
copied += sizeof(long);
out++;
printf("ptrace: copied %d bytes\n",copied);
}
return copied;
}
int main()
{
pid_t child;
long result;
struct user_regs_struct regs;
int status;
long addr = 0x601050;
size_t sz = sizeof(double);
long *buf = (long*)malloc(sz);
child = fork();
if(child == 0)
{
ptrace(PTRACE_TRACEME);
execl("./matmul", "matmul", NULL);
}
else
{
ptrace(PTRACE_GETREGS, child, &regs);
printf("ptrace: regs.rip : 0x%lx\n", regs.rip);
while(1)
{
read_mem(buf, child, addr, sz);
printf("ptrace: read(0x%lx) : %f\n", addr, (double)(*buf));
ptrace(PTRACE_CONT, child);
sleep(1);
}
}
return 0;
}
You don't seem to set a PTRACE_O_TRACEEXEC option. Failing to do so results in SIGTRAP being sent to tracee upon a call to exec; if it is not prepared, the default action is a termination with a core dump.

C:How Process communicate in linux

I want to count the number of processes that are created with a for 1,10 and where fork() si executed. The program is executed in linux. I really don't get how to use wait or WEXITSTATUS and I've spent hours on forums and still don't get it. Can someone help me, please?
Thanks,
Dragos
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int nr = 1;
int main()
{
int pid;
int i;
int stare;
for(i = 1; i<=10 ; i++)
{
pid = fork();
if( pid !=0 )
{
//parent
wait(&stare);
nr = nr + stare;
}
else
{
//child
nr++;
stare = WEXITSTATUS(nr);
exit(nr);
}
}
printf("\nNr: %d\n", nr);
}
The macros like WEXITSTATUS are used in the parent process to get the exit status after a wait call.
In the child process, it's enough to just return nr (or call exit with it as argument).
In the parent you use WEXITSTATUS like this:
if (wait(&stare) > 0)
{
if (WIFEXITED(stare))
nr += WEXITSTATUS(stare);
}
We must use the WIFEXITED check because otherwise the exit status is not valid.

Manipulating var from father in child process

Can someone pls explain why the output of the following program is 1 and not 2?
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int x = 1;
int *y = &x;
pid_t pid = fork();
if (pid == 0) {
*y = 2;
exit(0);
} else {
wait(NULL);
printf("father: %d\n", x);
}
return 1;
}
fork doesn't create a thread, it creates a whole new process.
The address space of the child is a copy of the parent's one, they don't share it.
Modifications done by the parent are not visible from the child, and vice-versa, unless the specifically set something up to do so (via shared memory segments for instance).

Resources