1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/*
@mindmaze_header@
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "tests-child-proc.h"
#include <stdio.h>
#include <stdlib.h>
#include <check.h>
#include <mmsysio.h>
#include <mmthread.h>
#define FDMAP_MAXLEN 16
LOCAL_SYMBOL
int run_as_process(mm_pid_t* pid_ptr, char * fn_name,
void* args, size_t argslen, int last_fd_kept)
{
struct mm_remap_fd fdmap[FDMAP_MAXLEN];
int rv, i, shm_fd, fdmap_len;
char mapfile_arg_str[64];
char* argv[] = {TESTS_CHILD_BIN, fn_name, mapfile_arg_str, NULL};
void* map;
shm_fd = mm_anon_shm();
ck_assert(shm_fd != -1);
mm_ftruncate(shm_fd, MM_PAGESZ);
map = mm_mapfile(shm_fd, 0, MM_PAGESZ, MM_MAP_RDWR|MM_MAP_SHARED);
ck_assert(map != NULL);
memcpy(map, args, argslen);
// Configure fdmap to keep all fd in child up to last_fd_kept
for (i = 0; i <= last_fd_kept; i++) {
fdmap[i].child_fd = i;
fdmap[i].parent_fd = i;
}
// Ensure shm_fd is inherited in child
fdmap_len = last_fd_kept+2;
sprintf(mapfile_arg_str, "mapfile-%i-4096", last_fd_kept+1);
fdmap[last_fd_kept+1].child_fd = last_fd_kept+1;
fdmap[last_fd_kept+1].parent_fd = shm_fd;
// Start process
rv = mm_spawn(pid_ptr, argv[0], fdmap_len, fdmap, 0, argv, NULL);
mm_unmap(map);
mm_close(shm_fd);
return rv;
}
/*
* _run_function(): takes a function and run it as a thread or a process.
* @id: id of the thread or the process returned
* @fn: the function to run
* @fn_name: the function name as a string. Filled by the run_function macro
* @args: arguments that will be passed to the function
* @argslen: length of the arguments. Filled by the run_function macro
* @run_mode: can be RUN_AS_THREAD, or RUN_AS_PROCESS
*
* This should not be called directly, use the run_function macro below instead.
*
* See mm_thr_create() and mm_spawn().
*
* the function ran should follow the prototype:
* intptr_t custom_fn(void *)
* The function is expected to return zero on success.
*
* Returns: 0 on success, aborts otherwise
*/
LOCAL_SYMBOL
int _run_function(thread_proc_id * id, intptr_t (*fn)(void*),
char * fn_name, void * args, size_t argslen, int run_mode)
{
union {
intptr_t (*proc)(void*);
void* (*thread)(void*);
} cast_fn;
int rv;
// Use union to cast function type (no compiler should warn this)
cast_fn.proc = fn;
switch (run_mode) {
case RUN_AS_THREAD:
rv = mm_thr_create(&id->thread_id, cast_fn.thread, args);
ck_assert_msg(rv == 0, "can't create thread for %s", fn_name);
break;
case RUN_AS_PROCESS:
rv = run_as_process(&id->proc_id, fn_name, args, argslen, 2);
ck_assert_msg(rv == 0, "can't create process for %s", fn_name);
break;
default:
ck_abort_msg("invalid mode (%i) with %s", run_mode, fn_name);
}
return 0;
}
/**
* clean_function(): clean a thread or a process that has been launched using run_function()
* @id: the thread or process id as filled by run_function()
* @run_mode: can be RUN_AS_THREAD, or RUN_AS_PROCESS
*/
LOCAL_SYMBOL
void clean_function(thread_proc_id id, int run_mode)
{
intptr_t iptrval;
int ival;
switch (run_mode) {
case RUN_AS_THREAD:
mm_thr_join(id.thread_id, (void**)&iptrval);
if (iptrval != 0) {
ck_abort_msg("thread returned %i", (int)iptrval);
}
break;
case RUN_AS_PROCESS:
if (mm_wait_process(id.proc_id, &ival) != 0
|| (ival ^ MM_WSTATUS_EXITED) != 0 ) {
ck_abort_msg("process returned %i\n", ival);
}
break;
default:
ck_assert_msg(0, "invalid mode %i", run_mode);
break;
}
}
|