Difference between revisions of "Fork system call"

From Teknologisk videncenter
Jump to: navigation, search
m
m (Magic or Qbit?)
Line 10: Line 10:
 
int main(void) {
 
int main(void) {
 
         if (fork()) {
 
         if (fork()) {
                 printf("Sand\n");
+
                 printf("True\n");
 
         } else {
 
         } else {
                 printf("Falsk\n");
+
                 printf("False\n");
 
         }
 
         }
 
         return(0);
 
         return(0);
Line 21: Line 21:
 
heth@emb3:~/bin/$ gcc process0.c -o process0
 
heth@emb3:~/bin/$ gcc process0.c -o process0
 
heth@emb3:~/bin/$ ./process0
 
heth@emb3:~/bin/$ ./process0
Sand
+
True
Falsk
+
False
 
</source>
 
</source>
 +
 
==What is fork==
 
==What is fork==
 
[[Fork system call|fork()]] creates a new process by duplicating the calling process.  The new process is referred to as the child process.  The calling process is referred to as the parent process.
 
[[Fork system call|fork()]] creates a new process by duplicating the calling process.  The new process is referred to as the child process.  The calling process is referred to as the parent process.

Revision as of 07:19, 19 December 2022

fork() is one of several functions to "spawn" a process

Use of fork

Magic or Qbit?

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 
 5 int main(void) {
 6         if (fork()) {
 7                 printf("True\n");
 8         } else {
 9                 printf("False\n");
10         }
11         return(0);
12 }

When running the above code:

heth@emb3:~/bin/$ gcc process0.c -o process0
heth@emb3:~/bin/$ ./process0
True
False

What is fork

fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.

  • PID - Process ID - the ID of a running process
  • PPID - Parent Process ID - default the ID of the process that created this process or 1 if the parent died.
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 
 5 
 6 int main(void) {
 7         printf("I am parent - my PPID is %d and my PID is %d\n", getppid(), getpid() );
 8 
 9         if (fork() == 0) {
10                 printf("I am child  - my PPID is %d and my PID is %d\n", getppid(), getpid() );
11                 printf("Child  dying\n");
12                 return(0);
13         }
14         printf("parent dying\n");
15         return(0);
16 }

Example of creating a daemon in Linux

Example of creating a daemon in Linux: (See systemd debian for systemd daemons)

  • setsid() - damon will be the session leader. Sets Session ID (SID) and Group ID (GID) to Process ID (PID)
  • Reopening stdin, stdout and stderr to /dev/null detaches the process from the controlling terminal and Parent PID is set to 1 (init or systemd - depending on Linux version/distribution)
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <syslog.h>
 5 void  daemon_create(void);
 6 
 7 int main(void) {
 8         printf("Starting my_daemon\n");
 9         openlog("my_daemon", LOG_INFO, LOG_DAEMON);
10         daemon_create();
11         for (int i=0; i < 100; i++) {
12                 syslog(LOG_INFO,"Countet to %d", i);
13                 sleep(2);
14         }
15         return(0);
16 }
17 
18 void  daemon_create(void) {
19     pid_t pid;
20 
21     pid = fork();
22     if(pid < 0){
23         syslog(LOG_ERR, "Error in fork: %m");
24         exit(1);
25     }
26     if(pid > 0) {
27         syslog(LOG_INFO, "Parent dying");
28         exit(0); // Parent die
29     }
30     if(setsid() < 0){ // Make child session leader
31         syslog(LOG_ERR, "Error in setsid: %m");
32         exit(2);
33         }
34         if (freopen("/dev/null", "r", stdin) == NULL
35         || freopen("/dev/null", "w", stdout) == NULL
36         || freopen("/dev/null", "w", stderr) == NULL ) {
37                 syslog(LOG_ERR, "When creating daemon freopen from STDIN/OUT/ERR failed: %m");
38                 exit(3);
39    }
40 }

Checking the daemon

  • Daemon detached from TTY - PPID is 1
  • Session and session group leader - SID and PGID same as PID
$ ps xo uname,pid,ppid,pgid,sid,tty,comm | grep -P '(my_daemon|COMMAND)'
USER         PID    PPID    PGID     SID TTY       COMMAND
heth      778254       1  778254  778254 ?        my_daemon
$ tail -f /var/log/sysg
Dec 20 12:37:59 emb3 my_daemon: Countet to 2
Dec 20 12:38:01 emb3 my_daemon: Countet to 3
Dec 20 12:38:03 emb3 my_daemon: Countet to 4
Dec 20 12:38:05 emb3 my_daemon: Countet to 5
...


Example of creating several processes

See same example in bash

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 #include <wait.h>
 5 
 6 void childprocess(char *name, int count_to) {
 7         int counter = 0;
 8 
 9         printf("My name is %s and my PID is %d\n", name, getpid());
10 
11         while (counter < count_to) {
12                 sleep(1);
13                 counter = counter +1;
14                 printf("%s counted to %i\n", name, counter);
15         }
16         printf("%s signing off\n", name);
17 }
18 
19 
20 int main(void) {
21         int wstatus; // Used by c wait function
22 
23         printf("I am the main function and my PID is %i\n", getpid());
24 
25         if (fork() == 0) { // fork returns 0 for child
26                 childprocess("Hans", 5);
27                 return(0);      // Child process finished
28         }
29 
30         if (fork() == 0) {
31                 childprocess("Ulla", 3);
32                 return(0);
33         }
34 
35         while(wait(&wstatus) > 0);
36         printf("Main signing off\n");
37         return(0);
38 }

Parent and child with different code

If we want a parent and a child to execute different code and share a resource, for example a server that send information to a client.

Three files:

  1. my_system.c - forks and starts the server code as parent and the client code as child.
  2. server.c"' - contains the server code
  3. client.c - contains the client code

Typical output when starting my_system

Note:

  • Server executable running with the parent PID
  • Client executable running with the child PID
Starting server as parent - my PID is 2644553
Starting client as child  - my PID is 2644554
Server started my PID is 2644553
Client started my PID is 2644554
Client received: hello: 1
Client received: hello: 2
Client received: hello: 3
Client received: hello: 4
Client received: hello: 5
Server signing out
Client signing out

my_system.c

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 
 5 int main()
 6 {
 7         int arr[2];
 8         char argv[50];
 9         pipe(arr);
10         if(fork())
11         {
12                 printf("Starting server as parent - my PID is %d\n", getpid());
13                 fflush(stdout);
14                 close(arr[0]);
15                 sprintf(argv,"%d",arr[1]);
16                 execlp("./server","server",argv,NULL);
17         }
18         else
19         {
20                 printf("Starting client as child  - my PID is %d\n", getpid());
21                 fflush(stdout);
22                 close(arr[1]);
23                 sprintf(argv,"%d",arr[0]);
24                 execlp("./client","client",argv,NULL);
25         }
26         return 1;
27 }

server.c

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <unistd.h>
 4 #include <stdlib.h>
 5 #include <string.h>
 6 
 7 int main(int argc,char *argv[])
 8 {
 9         char buf[40]="hello";
10         int fd,i;
11 
12         fd = atoi(argv[1]);
13         printf("Server started my PID is %d\n", getpid());
14         for (i=1; i <= 5; i++) {
15                 sprintf(buf,"hello: %d",i);
16                 write(fd,buf,strlen(buf)+1);
17                 sleep(1);
18         }
19         buf[0] == 0;
20         close(fd);
21         puts("Server signing out");
22 
23         return 0;
24 }

client.c

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 #include <stdlib.h>
 5 
 6 int main(int argc,char *argv[])
 7 {
 8         char buf[11];
 9         int fd;
10 
11         printf("Client started my PID is %d\n", getpid());
12         fd = atoi(argv[1]);
13         while(read(fd,buf,10) > 0)
14         {
15                 printf("Client received: %s\n",buf);
16         }
17         close(fd);
18         printf("Client signing out\n");
19         return 0;
20 }


Links