/* * 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 the test script execution module. * * Threading And Locking Model * * There are two threads in our process: * * 1) main thread: this is the thread that invokes main() and * does most of the work of test execution. * * 2) blocking system call thread: this is the thread that * executes blocking system calls. * * To keep things as simple as possible, there is a single global * mutex, state->mutex, which protects all global data (data that is * not purely local to a function). * * The main thread holds the global mutex for almost the entire * duration of a test run. It unlocks the mutex only for: * * o sleeping while waiting for the start time of the next event * o waiting for the system call thread to block on a system call * o waiting for the system call thread to exit * * The system call thread runs briefly, only to execute blocking * system calls, and holds the global mutex for the entire duration it * is running, from interpreting system call arguments to processing * system call outputs. It unlocks the mutex only for: * * o sleeping while waiting for the start time of the system call * o the actual function call to invoke the blocking system call itself */ #ifndef __RUN_H__ #define __RUN_H__ #include "types.h" #include <netinet/in.h> #include <pthread.h> #include <stdlib.h> #include <sys/socket.h> #include "code.h" #include "config.h" #include "netdev.h" #include "run_packet.h" #include "run_system_call.h" #include "script.h" #include "socket.h" #include "wire_client.h" /* Public top-level entry point for executing a test script */ extern void run_script(struct config *config, struct script *script); /* Public entry-point to parse a script and finalize config. If the * script_buffer is provided, parse that. Otherwise, read the file * with the given path, parse that. */ extern int parse_script_and_set_config(int argc, char *argv[], struct config *config, struct script *script, const char *script_path, const char *script_buffer); /* Private implementation details follow below... */ /* All the runtime state for a test. */ struct state { pthread_mutex_t mutex; /* global lock for all global state */ struct config *config; /* test configuration */ struct netdev *netdev; /* for sending/receiving TCP packets */ struct packets *packets; /* for processing packets */ struct syscalls *syscalls; /* for running system calls */ struct socket *sockets; /* list of all live sockets */ struct socket *socket_under_test; /* socket handling packets */ struct script *script; /* script we're running */ struct event *event; /* the current event */ struct event *last_event; /* previous event */ struct code_state *code; /* for running post-processing code */ struct wire_client *wire_client; /* for on-the-wire tests */ s64 script_start_time_usecs; /* time of first event in script */ s64 script_last_time_usecs; /* time of previous event in script */ s64 live_start_time_usecs; /* time of first event in live test */ }; /* Allocate all run-time state for executing a test script. */ extern struct state *state_new(struct config *config, struct script *script, struct netdev *netdev); /* Free all run-time state for a test. */ void state_free(struct state *state, int about_to_die); /* Grab the global lock for all global state. */ static inline void run_lock(struct state *state) { if (pthread_mutex_lock(&state->mutex) != 0) die_perror("pthread_mutex_lock"); } /* Release the global lock for all global state. */ static inline void run_unlock(struct state *state) { if (pthread_mutex_unlock(&state->mutex) != 0) die_perror("pthread_mutex_unlock"); } /* Get the wall clock time of day in microseconds. */ extern s64 now_usecs(void); /* Convert script time to live wall clock time. */ static inline s64 script_time_to_live_time_usecs(struct state *state, s64 script_time_usecs) { s64 offset_usecs = script_time_usecs - state->script_start_time_usecs; s64 live_time_usecs = state->live_start_time_usecs + offset_usecs; return live_time_usecs; } /* Convert live wall clock time to script time. */ static inline s64 live_time_to_script_time_usecs(struct state *state, s64 live_time_usecs) { s64 offset_usecs = live_time_usecs - state->live_start_time_usecs; s64 script_time_usecs = state->script_start_time_usecs + offset_usecs; return script_time_usecs; } /* * See if something that happened at the given actual live wall time * in microseconds happened reasonably close to the time at which we * wanted it to happen in the script. verify_time compares the * given script and live times and returns STATUS_OK on success or on * failure returns STATUS_ERR and fills in *error using the given * description. The check_event_time variant is a shortcut * for the common case: it looks at the current event and on failure * it prints the error message to stderr and exits with an error * status. For time ranges the end time is specified in script_usecs_end. */ extern int verify_time(struct state *state, enum event_time_t time_type, s64 script_usecs, s64 script_usecs_end, s64 live_usecs, const char *description, char **error); extern void check_event_time(struct state *state, s64 live_usecs); /* Set the start (and end time, if applicable) for the event if it * uses wildcard or relative timing. */ extern void adjust_relative_event_times(struct state *state, struct event *event); /* * Sleep and/or spin until the time at which we want the current event * to happen. */ extern void wait_for_event(struct state *state); /* Advance the interpreter state to the next event. */ extern int get_next_event(struct state *state, char **error); /* Set a higher priority for ourselves, to reduce test timing noise. */ extern void set_scheduling_priority(void); /* Try to pin our pages into RAM. */ extern void lock_memory(void); #endif /* __RUN_H__ */