Skip to content

Commit

Permalink
tests: add fork_func
Browse files Browse the repository at this point in the history
  • Loading branch information
gperciva committed Jan 14, 2024
1 parent ebfe5c8 commit 19efda2
Show file tree
Hide file tree
Showing 13 changed files with 599 additions and 0 deletions.
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
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}"
}
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 19efda2

Please sign in to comment.