aboutsummaryrefslogtreecommitdiffstats
path: root/test/packetdrill/run_system_call.h
blob: 03a3d2710ad0641b942a2d661d27c1d439407e3a (plain)
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
/*
 * Copyright 2013 Google Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
/*
 * Author: ncardwell@google.com (Neal Cardwell)
 *
 * Interface for a module to execute a system call from a test script.
 */

#ifndef __RUN_SYSTEM_CALL_H__
#define __RUN_SYSTEM_CALL_H__

#include "types.h"

#include <pthread.h>
#include "script.h"

struct state;

/* States in which the system call thread can be. */
enum syscall_state_t {
	SYSCALL_IDLE,		/* system call thread is idle */
	SYSCALL_ENQUEUED,	/* blocking system call is ready to execute */
	SYSCALL_RUNNING,	/* system call is running */
	SYSCALL_DONE,		/* system call is done running */
	SYSCALL_EXITING,	/* process is exiting */
};

/* Internal state for the system call module, including the "syscall
 * thread", which handles blocking system calls.
 */
struct syscalls {
	enum syscall_state_t state;	/* current state of syscall thread */
	struct event *event;		/* current system call it's running */
	s64 live_end_usecs;		/* time of last system call return */

	/* Handles for the syscall thread, for blocking system calls. */
	pthread_t thread;		/* pthread thread handle */
	pid_t thread_id;		/* kernel thread ID  */

	/* The main thread waits on this condition variable. The
	 * system call thread signals this when it has finished
	 * executing a blocking system call and is now idle and ready
	 * to execute another blocking system call.
	 */
	pthread_cond_t idle;

	/* The system call thread waits on this condition
	 * variable. The main thread signals this when it has enqueued
	 * a blocking system call to execute, and thus the system call
	 * thread should wake up and execute that system call. The
	 * main thread also signals this when it's time to exit.
	 */
	pthread_cond_t enqueued;

	/* The main thread waits on this condition variable. The
	 * system call thread signals this after it has dequeued the
	 * system call and just before it invokes the system call, at
	 * which point the main thread should wake up to continue test
	 * execution.
	 */
	pthread_cond_t dequeued;
};

/* Info for a nla type */
struct nla_type_info {
	const char* name;
	int length;
};

/* Allocate and return internal state for the system call module. */
extern struct syscalls *syscalls_new(struct state *state);

/* Tear down a syscalls and free up the resources it has allocated. */
extern void syscalls_free(struct state *state,
			  struct syscalls *syscalls);

/* Execute the given system call event. The system call may be
 * expected to block for a while, or it may be expected to return
 * immediately. To keep things simple, currently we only support
 * at most one blocking system call at a time; if a script attempts to
 * start a second blocking call before the first blocking call has
 * returned then this second call raises a runtime error.
 */
void run_system_call_event(struct state *state,
			   struct event *event,
			   struct syscall_spec *syscall);

#endif /* __RUN_SYSTEM_CALL_H__ */