Standards / Extensions | C or C++ | Dependencies |
---|---|---|
Single UNIX Specification, Version 3 |
both | z/OS V1R9 |
#define _UNIX03_THREADS
#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void));
The pthread_atfork() function registers fork handlers to be called before and after fork(), in the context of the thread that called fork(). Fork handler functions may be named for execution at the following three points in thread processing:
If any argument to pthread_atfork() is NULL, the call does not register a handler to be invoked at the point corresponding to that argument.
The order of calls to pthread_atfork() is significant. The parent and child fork handlers are called in the order in which they were established by calls to pthread_atfork(). The prepare fork handlers are called in the opposite order.
The intended purpose of pthread_atfork() is to provide a mechanism for maintaining the consistency of mutex locks between parent and child processes. The handlers are expected to be straightforward programs, designed simply to manage the synchronization variables and must return to ensure that all registered handlers are called. Historically, the prepare handler acquired needed mutex locks, and the parent and child handlers released them. Unfortunately, this usage is not practical on the z/OS® platform and is not guaranteed to be portable in the current UNIX standards. When the parent process is multi-threaded (invoked pthread_create() at least once), the child process can only safely call async-signal-safe functions before it invokes an exec() family function. This restriction was added to the POSIX.1 standard in 1996. Because functions such as pthread_mutex_lock() and pthread_mutex_unlock() are not async-signal-safe, unpredictable results may occur if they are used in a child handler.
If successful, pthread_atfork() returns zero; otherwise, it returns an error number.
CELEBP60
⁄* CELEBP60 *⁄
⁄* Example using SUSv3 pthread_atfork() interface *⁄
#define _UNIX03_THREADS 1
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys⁄types.h>
#include <sys⁄wait.h>
#include <stdlib.h>
#include <errno.h>
char fn_c[] = "childq.out";
char fn_p[] = "parentside.out";
int fd_c;
int fd_p;
void prep1(void) {
char buff[80] = "prep1\n";
write(4,buff,sizeof(buff));
}
void prep2(void) {
char buff[80] = "prep2\n";
write(4,buff,sizeof(buff));
}
void prep3(void) {
char buff[80] = "prep3\n";
write(4,buff,sizeof(buff));
}
void parent1(void) {
char buff[80] = "parent1\n";
write(4,buff,sizeof(buff));
}
void parent2(void) {
char buff[80] = "parent2\n";
write(4,buff,sizeof(buff));
}
void parent3(void) {
char buff[80] = "parent3\n";
write(4,buff,sizeof(buff));
}
void child1(void) {
char buff[80] = "child1\n";
write(3,buff,sizeof(buff));
}
void child2(void) {
char buff[80] = "child2\n";
write(3,buff,sizeof(buff));
}
void child3(void) {
char buff[80] = "child3\n";
write(3,buff,sizeof(buff));
}
void *thread1(void *arg) {
printf("Thread1: Hello from the thread.\n");
}
int main(void)
{
pthread_t thid;
int rc, ret;
pid_t pid;
int status;
char header[30] = "Called Child Handlers\n";
if (pthread_create(&thid, NULL, thread1, NULL) != 0) {
perror("pthread_create() error");
exit(3);
}
if (pthread_join(thid, NULL) != 0) {
perror("pthread_join() error");
exit(5);
} else {
printf("IPT: pthread_join success! Thread 1 should be finished now.\n");
printf("IPT: Prepare to fork!!!\n");
}
⁄*-----------------------------------------*⁄
⁄*| Start atfork handler calls in parent *⁄
⁄*-----------------------------------------*⁄
⁄* Register call 1 *⁄
rc = pthread_atfork(&prep1, &parent2, &child3);
if (rc != 0) {
perror("IPT: pthread_atfork() error [Call #1]");
printf(" rc= %d, errno: %d, ejr: %08x\n", rc, errno, __errno2());
}
⁄* Register call 2 *⁄
rc = pthread_atfork(&prep2, &parent3, &child1);
if (rc != 0) {
perror("IPT: pthread_atfork() error [Call #2]");
printf(" rc= %d, errno: %d, ejr: %08x\n", rc, errno, __errno2());
}
⁄* Register call 3 *⁄
rc = pthread_atfork(&prep3, &parent1, NULL);
if (rc != 0) {
perror("IPT: pthread_atfork() error [Call #3]");
printf(" rc= %d, errno: %d, ejr: %08x\n", rc, errno, __errno2());
}
⁄* Create output files to expose the execution of fork handlers. *⁄
if ((fd_c = creat(fn_c, S_IWUSR)) < 0)
perror("creat() error");
else
printf("Created %s and assigned fd= %d\n", fn_c, fd_c);
if ((ret = write(fd_c,header,30)) == -1)
perror("write() error");
else
printf("Write() wrote %d bytes in %s\n", ret, fn_c);
if ((fd_p = creat(fn_p, S_IWUSR)) < 0)
perror("creat() error");
else
printf("Created %s and assigned fd= %d\n", fn_p, fd_p);
if ((ret = write(fd_p,header,30)) == -1)
perror("write() error");
else
printf("Write() wrote %d bytes in %s\n", ret, fn_p);
pid = fork();
if (pid < 0)
perror("IPT: fork() error");
else {
if (pid == 0) {
printf("Child: I am the child!\n");
printf("Child: My PID= %d, parent= %d\n", (int)getpid(),
(int)getppid());
exit(0);
} else {
printf("Parent: I am the parent!\n");
printf("Parent: My PID= %d, child PID= %d\n", (int)getpid(), (int)pid);
if (wait(&status) == -1)
perror("Parent: wait() error");
else if (WIFEXITED(status))
printf("Child exited with status: %d\n",WEXITSTATUS(status));
else
printf("Child did not exit successfully\n");
close(fd_c);
close(fd_p);
}
}
}