Skip to content

Commit

Permalink
Merge pull request #487 from Tarsnap/fork-func
Browse files Browse the repository at this point in the history
Add fork_func
  • Loading branch information
cperciva authored Jan 14, 2024
2 parents bfffdd7 + 5fe2b4f commit 4b2eb56
Show file tree
Hide file tree
Showing 22 changed files with 799 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
/tests/daemonize/test_daemonize
/tests/elasticarray/test_elasticarray
/tests/events/test_events
/tests/fork_func/test_fork_func
/tests/getopt-longjmp/test_getopt_longjmp
/tests/getopt/test_getopt
/tests/heap/test_heap
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ TESTS= perftests/http \
tests/daemonize \
tests/elasticarray \
tests/events \
tests/fork_func \
tests/getopt \
tests/getopt-longjmp \
tests/heap \
Expand Down
1 change: 1 addition & 0 deletions Makefile.BSD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TESTS= perftests/http \
tests/daemonize \
tests/elasticarray \
tests/events \
tests/fork_func \
tests/getopt \
tests/getopt-longjmp \
tests/heap \
Expand Down
4 changes: 3 additions & 1 deletion liball/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.POSIX:
# AUTOGENERATED FILE, DO NOT EDIT
LIB=liball.a
SRCS=crc32c.c crc32c_arm.c crc32c_sse42.c md5.c sha1.c sha256.c sha256_arm.c sha256_shani.c sha256_sse2.c aws_readkeys.c aws_sign.c cpusupport_arm_aes.c cpusupport_arm_crc32_64.c cpusupport_arm_sha256.c cpusupport_x86_aesni.c cpusupport_x86_rdrand.c cpusupport_x86_shani.c cpusupport_x86_sse2.c cpusupport_x86_sse42.c cpusupport_x86_ssse3.c crypto_aes.c crypto_aes_aesni.c crypto_aes_arm.c crypto_aesctr.c crypto_aesctr_aesni.c crypto_aesctr_arm.c crypto_dh.c crypto_dh_group14.c crypto_entropy.c crypto_entropy_rdrand.c crypto_verify_bytes.c elasticarray.c elasticqueue.c ptrheap.c seqptrmap.c timerqueue.c events.c events_immediate.c events_network.c events_network_selectstats.c events_timer.c http.c https.c netbuf_read.c netbuf_ssl.c netbuf_write.c network_accept.c network_connect.c network_read.c network_write.c network_ssl.c network_ssl_compat.c asprintf.c b64encode.c daemonize.c entropy.c getopt.c hexify.c humansize.c insecure_memzero.c json.c monoclock.c noeintr.c perftest.c readpass.c readpass_file.c setgroups_none.c setuidgid.c sock.c sock_util.c ttyfd.c warnp.c
SRCS=crc32c.c crc32c_arm.c crc32c_sse42.c md5.c sha1.c sha256.c sha256_arm.c sha256_shani.c sha256_sse2.c aws_readkeys.c aws_sign.c cpusupport_arm_aes.c cpusupport_arm_crc32_64.c cpusupport_arm_sha256.c cpusupport_x86_aesni.c cpusupport_x86_rdrand.c cpusupport_x86_shani.c cpusupport_x86_sse2.c cpusupport_x86_sse42.c cpusupport_x86_ssse3.c crypto_aes.c crypto_aes_aesni.c crypto_aes_arm.c crypto_aesctr.c crypto_aesctr_aesni.c crypto_aesctr_arm.c crypto_dh.c crypto_dh_group14.c crypto_entropy.c crypto_entropy_rdrand.c crypto_verify_bytes.c elasticarray.c elasticqueue.c ptrheap.c seqptrmap.c timerqueue.c events.c events_immediate.c events_network.c events_network_selectstats.c events_timer.c http.c https.c netbuf_read.c netbuf_ssl.c netbuf_write.c network_accept.c network_connect.c network_read.c network_write.c network_ssl.c network_ssl_compat.c asprintf.c b64encode.c daemonize.c entropy.c fork_func.c getopt.c hexify.c humansize.c insecure_memzero.c json.c monoclock.c noeintr.c perftest.c readpass.c readpass_file.c setgroups_none.c setuidgid.c sock.c sock_util.c ttyfd.c warnp.c
IDIRS=-I../alg -I../aws -I../cpusupport -I../crypto -I../datastruct -I../events -I../http -I../netbuf -I../network -I../network_ssl -I../util -I../external/queue
SUBDIR_DEPTH=..
RELATIVE_DIR=liball
Expand Down Expand Up @@ -133,6 +133,8 @@ daemonize.o: ../util/daemonize.c ../util/noeintr.h ../util/warnp.h ../util/daemo
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c ../util/daemonize.c -o daemonize.o
entropy.o: ../util/entropy.c ../util/warnp.h ../util/entropy.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c ../util/entropy.c -o entropy.o
fork_func.o: ../util/fork_func.c ../util/warnp.h ../util/fork_func.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c ../util/fork_func.c -o fork_func.o
getopt.o: ../util/getopt.c ../util/getopt.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c ../util/getopt.c -o getopt.o
hexify.o: ../util/hexify.c ../util/hexify.h
Expand Down
1 change: 1 addition & 0 deletions liball/Makefile.BSD
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ SRCS += asprintf.c
SRCS += b64encode.c
SRCS += daemonize.c
SRCS += entropy.c
SRCS += fork_func.c
SRCS += getopt.c
SRCS += hexify.c
SRCS += humansize.c
Expand Down
37 changes: 37 additions & 0 deletions tests/24-fork-func.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

### Constants
c_valgrind_min=1
spawning="${s_basename}-spawning.txt"
waited="${s_basename}-waited.txt"

### Actual command
scenario_cmd() {
cd "${scriptdir}/fork_func" || exit

setup_check "test_fork_func -x"
# Special handling for multiple forks.
c_valgrind_cmd=$(valgrind_setup "valgrind-parent")
${c_valgrind_cmd} ./test_fork_func -x
echo "$?" > "${c_exitfile}"

setup_check "test_fork_func -e"
# Special handling for multiple forks.
c_valgrind_cmd=$(valgrind_setup "valgrind-parent")
${c_valgrind_cmd} ./test_fork_func -e
echo "$?" > "${c_exitfile}"

setup_check "test_fork_func -c"
# Special handling for multiple forks.
c_valgrind_cmd=$(valgrind_setup "valgrind-parent")
${c_valgrind_cmd} ./test_fork_func -c >"${spawning}" 2>"${waited}"
echo "$?" > "${c_exitfile}"

setup_check "test_fork_func -c spawning"
cmp "${spawning}" "${scriptdir}/fork_func/check_order_spawning.good"
echo "$?" > "${c_exitfile}"

setup_check "test_fork_func -c waited"
cmp "${waited}" "${scriptdir}/fork_func/check_order_waited.good"
echo "$?" > "${c_exitfile}"
}
35 changes: 35 additions & 0 deletions tests/fork_func/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.POSIX:
# AUTOGENERATED FILE, DO NOT EDIT
PROG=test_fork_func
SRCS=main.c check_exec.c check_exit.c check_order.c check_perftest.c
IDIRS=-I../../util
LDADD_REQ=-lpthread
SUBDIR_DEPTH=../..
RELATIVE_DIR=tests/fork_func
LIBALL=../../liball/liball.a ../../liball/optional_mutex_pthread/liball_optional_mutex_pthread.a

all:
if [ -z "$${HAVE_BUILD_FLAGS}" ]; then \
cd ${SUBDIR_DEPTH}; \
${MAKE} BUILD_SUBDIR=${RELATIVE_DIR} \
BUILD_TARGET=${PROG} buildsubdir; \
else \
${MAKE} ${PROG}; \
fi

clean:
rm -f ${PROG} ${SRCS:.c=.o}

${PROG}:${SRCS:.c=.o} ${LIBALL}
${CC} -o ${PROG} ${SRCS:.c=.o} ${LIBALL} ${LDFLAGS} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX}

main.o: main.c ../../util/getopt.h ../../util/parsenum.h ../../util/warnp.h check.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c main.c -o main.o
check_exec.o: check_exec.c ../../util/fork_func.h ../../util/warnp.h check.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c check_exec.c -o check_exec.o
check_exit.o: check_exit.c ../../util/fork_func.h check.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c check_exit.c -o check_exit.o
check_order.o: check_order.c ../../util/fork_func.h ../../util/millisleep.h ../../util/warnp.h check.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c check_order.c -o check_order.o
check_perftest.o: check_perftest.c ../../util/fork_func.h ../../util/millisleep.h ../../util/monoclock.h ../../util/warnp.h check.h
${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c check_perftest.c -o check_perftest.o
23 changes: 23 additions & 0 deletions tests/fork_func/Makefile.BSD
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Program name.
PROG = test_fork_func

# Don't install it.
NOINST = 1

# Library code required
LDADD_REQ = -lpthread

# Useful relative directories
LIBCPERCIVA_DIR = ../..

# Main test code
SRCS = main.c
SRCS += check_exec.c
SRCS += check_exit.c
SRCS += check_order.c
SRCS += check_perftest.c

# libcperciva includes
IDIRS += -I${LIBCPERCIVA_DIR}/util

.include <bsd.prog.mk>
28 changes: 28 additions & 0 deletions tests/fork_func/check.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef CHECK_H_
#define CHECK_H_

/**
* check_exit(void):
* Check that fork_func() works with exit codes.
*/
int check_exit(void);

/**
* check_exec(void):
* Check that fork_func() works with an exec* function.
*/
int check_exec(void);

/**
* check_order(void):
* Check that fork_func() doesn't impose any order on multiple functions.
*/
int check_order(void);

/**
* check_perftest(void):
* Check the amount of delay added by func_fork() and func_fork_wait().
*/
int check_perftest(int child_ms, int num_reps);

#endif /* !CHECK_H_ */
45 changes: 45 additions & 0 deletions tests/fork_func/check_exec.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <unistd.h>

#include "fork_func.h"
#include "warnp.h"

#include "check.h"

static int
func_exec(void * cookie)
{

(void)cookie; /* UNUSED */

/* Execute the "true" binary found in the $PATH. */
if (execlp("true", "true", NULL))
warnp("execvp");

/* We should never reach this. */
return (127);
}

/**
* check_exec(void):
* Check that fork_func() works with an exec* function.
*/
int
check_exec(void)
{
pid_t pid;

/* Fork. */
if ((pid = fork_func(func_exec, NULL) == -1))
goto err0;

/* Check that it didn't fail. */
if (fork_func_wait(pid) != 0)
goto err0;

/* Success! */
return (0);

err0:
/* Failure! */
return (-1);
}
45 changes: 45 additions & 0 deletions tests/fork_func/check_exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <sys/types.h>

#include "fork_func.h"

#include "check.h"

static int
func_exit(void * cookie)
{
int * exitcode_p = (int *)cookie;

/* Return the specified exit code. */
return (*exitcode_p);
}

/**
* check_exit(void):
* Check that fork_func() works with exit codes.
*/
int
check_exit(void)
{
pid_t pid;
int i;
int rc;

for (i = 0; i < 4; i++) {
/* Fork. */
if ((pid = fork_func(func_exit, &i)) == -1)
goto err0;

/* Check the result. */
if ((rc = fork_func_wait(pid)) == -1)
goto err0;
if (rc != i)
goto err0;
}

/* Success! */
return (0);

err0:
/* Failure! */
return (-1);
}
103 changes: 103 additions & 0 deletions tests/fork_func/check_order.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#include <sys/types.h>

#include <stdio.h>

#include "fork_func.h"
#include "millisleep.h"
#include "warnp.h"

#include "check.h"

/**
* Do a "sleep sort". This isn't guaranteed to sort successfully, but it's
* very unlikely that any processes will be delayed by enough for it to fail.
*
* We want to output two different lists: the "spawning" messages, and the
* "waited" messages. This allows the test to be more resistant to systems
* having different overheads for fork().
*
* To achieve this, the "spawning" messages go to stdout, while the "waited"
* messages go to stderr.
*/

#define NUM_PROCESSES 5
static int SLEEP_SORT_MS[5] = {200, 800, 0, 600, 400};

/* Wait X milliseconds, then print to stderr. */
static int
sleep_print_func(void * cookie)
{
int ms = *((int *)cookie);

/* Wait. */
millisleep((size_t)ms);

/* Write the "waited" messages to stderr. */
if (fprintf(stderr, "waited %i ms\n", ms) < 0) {
warnp("fprintf");
goto err0;
}

/* Success! */
return (0);

err0:
/* Failure! */
return (-1);
}

/**
* check_order(void):
* Check that fork_func() doesn't impose any order on multiple functions.
*/
int
check_order(void)
{
pid_t pids[NUM_PROCESSES];
int i;

/*-
* We want to output two different lists: the "spawning"
* messages, and the "waited" messages. This allows the test
* to be more resistant to systems having different overheads
* for fork().
*
* To achieve this, the "spawning" messages go to stdout,
* while the "waited" messages go to stderr.
*/

/* Write the "spawning" messages to stdout. */
for (i = 0; i < NUM_PROCESSES; i++) {
if (fprintf(stdout, "spawning a process to wait %i ms\n",
SLEEP_SORT_MS[i]) < 0) {
warnp("fprintf");
goto err0;
}
}

/* Flush stdout so that its buffer isn't duplicated in the forks. */
if (fflush(stdout)) {
warnp("fflush");
goto err0;
}

/* Spawn the processes. */
for (i = 0; i < NUM_PROCESSES; i++) {
if ((pids[i] = fork_func(sleep_print_func,
&SLEEP_SORT_MS[i])) == -1)
goto err0;
}

/* Wait for the processes to finish. */
for (i = 0; i < NUM_PROCESSES; i++) {
if (fork_func_wait(pids[i]))
goto err0;
}

/* Success! */
return (0);

err0:
/* Failure! */
return (-1);
}
5 changes: 5 additions & 0 deletions tests/fork_func/check_order_spawning.good
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
spawning a process to wait 200 ms
spawning a process to wait 800 ms
spawning a process to wait 0 ms
spawning a process to wait 600 ms
spawning a process to wait 400 ms
5 changes: 5 additions & 0 deletions tests/fork_func/check_order_waited.good
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
waited 0 ms
waited 200 ms
waited 400 ms
waited 600 ms
waited 800 ms
Loading

0 comments on commit 4b2eb56

Please sign in to comment.