File: tests-run-func.c

package info (click to toggle)
mmlib 1.4.2-2.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,716 kB
  • sloc: ansic: 18,071; makefile: 431; sh: 135; python: 63
file content (140 lines) | stat: -rw-r--r-- 3,505 bytes parent folder | download
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;
	}
}