-
Notifications
You must be signed in to change notification settings - Fork 0
run programs on a simulated time
License
sgerwk/timeserver
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
run programs on a simulated time examples -------- start three programs, advance their time by 24 seconds, then 321, etc: timeserver # server timeexec program1 args # start first program timeexec program2 args # start second program timeexec program3 args # start third program timerun 24 # advance time for 24 seconds timerun 321 # other 321 seconds timerun # advance time up the next wakeup time timerun 10 # other 10 seconds run cron under simulated time: timeserver -t now timeexec crond timerun ... programs -------- timeserver centralized handling of time; receive all requests to sleep(), nanosleep(), time(), gettimeofday() and clock_gettime() from the clients; reply to them according to the simulated time arguments: see man page timexec + timeclient.so run a program in the simulated time; intercept the calls to sleep() nanosleep(), time(), gettimeofday() and clock_gettime() nd redirect them to the timeserver timerun run the simulated time for the given number of seconds; default is the time left to the next wakeup of a program implementation -------------- timeexec runs the program under the timeclient.so preload library; this library intercepts all calls to sleep(), nanosleep(), time(), gettimeofday() and clock_gettime() and make them send ipc messages to the server in particular, time(), gettimeofday() and clock_gettime() send messages asking the server for the current time, which the server answer immediately; the time is randomly increased by a second at each query to allow busywaiting; sleep() and nanosleep() send a similar message to the server, which however replies only when the wakeup time is reached; this way, the client is blocked until then since the server wakes sleeping clients at different times, each client needs a unique identifier; clients register with the server to receive that unique identifier; this is also the case for their chidren, which still have the system calls redirected to the timeserver; this is why libclient.so also intercepts fork(), execve() and execle(); it also intercepts _exit() and exit_group() to deregister clients; however, termination by signals is not done by calling _exit; clients terminated this way do not unregister; the timeserver checks for their termination by their pid from time to time messages -------- since the server listens to messages of different types at the same time, and msgrcv() only allow that by specifying a maximal message type, the messages directed to the server need to be of type under a certain bound TOSERVER controller->server RUN the timeserver is instructed to run the simulation for a given number of seconds; if this number is zero, run until any of the clients wakes up from sleep client->server REGISTER the client register with the timeserver; reply is a message of type CLIENTID containing the client id PID the client tells the server its pid; this information could not be included in the REGISTER message (see the discussion on the CLIENTID message); no reply is sent UNREGISTER the client unregister with the timeserver; no reply sent SLEEP a client called sleep() or nanosleep(); the server replies with a message of type WAKE+client_id when the wakeup time is reached; the client is blocked waiting for this message until then CANCEL while a client was waiting for the wakeup message, an interrupt arrived; in this condition, the call to sleep() or nanosleep() must terminate immediately; however, the server still has a wakeup message programmed to be sent; the CANCEL message tells it to send that wakeup event immediately, if not already QUERY the client called time(), gettimeofday() or clock_gettime(); the server immediately replies with the current time in the simulation in a message of type TIME; the time is increased by one (with a certain probability) at each query to allow for busywaiting server->client CLIENTID in response to a REGISTER message, the server sends the client_id in this message; if two clients do this at about the same time, they may receive each the CLIENTID message of the other; this is irrelevant, all that matters is that each client receives a unique id TIME the server sends this type of messages in response to a QUERY message; it contains the current simulated time; again, which client receives which message is irrelevant WAKE+client_id message sent by the server at the appropriate time to wake a client that sent a SLEEP message; this is the only message that really needs to be delivered to a specific client timeout ------- ideally, the timeserver could wait until all clients are sleeping, and then jump to the first wakeup time; in practice, this is not possible for two reasons: a. even if all registered clients are sleeping, jumping may be incorrect this happens when the last non-sleeping client forks and then sleeps before the child registers; in this case, the timeserver does not realize that there is a new client and jumps to first wakeup time before serving the requests from the new client this also happens if the last non-sleeping client executes another program: it unregisters before execve() and registers again afterwards; after the deregistration, the timeserver believes that no clients are running b. even if some clients are running, jumping may be necessary the non-sleeping clients may run a long time without sending requests to the timeserver; if the timeserver just waits for messages, it does not get any, so the sleeping clients are not waken for these reason, the timeserver reads messages with a timeout; the timeout allows clients to run some time before making requests to the timeserver, and to finish a fork or execve; only if no message is read within the given time, the timeserver jumps to the next wakeup time with option -j, instead of the next wakeup time the timeserver increases time by the given number of seconds signals ------- programs run with the timeclient.so preload library register with the timeserver when they start and deregister when they end; this is done by rerouting the fork(), exec(), _exit() and exit_group() system calls unfortunately, processes killed by signals execute neither _exit() nor exit_group(); for this reason, at the appropriate time the timeserver checks whether all clients are still alive; this is why clients send their pid todo ---- 1. include nanoseconds in the time; make nanosleep() the main function and sleep() call it; the same for time(), gettimeofday(), and clock_gettime() 2. use some other file instead of /dev/null, so that more instances of timeserver can be run at the same time 3. while the timeout for long-running clients is necessary (albeit arbitrary in length), keeping track of the non-sleeping clients exactly is possible have messages to temporarily increase/decrease the number of registered (non-sleeping) clients; before forking, the client sends an INCREASE message; the DECREASE is sent by it if the fork fails, otherwise is sent by the child after registering the same is done across an execve; this requires an enviroment variable to be passed to execve so that the constructor the known whether it has been called by the execve() of timeclient.c (and then it has to decrease after registering) or by timeexec.c (do not decrease); otherwise: timeexec.c sends the increase before execve what complicates the mechanism is that processes may be interrupted by a signal after the increase but before the decrease; this would require the pid to be be stored in the server; since a client may fork multiple times in a row before the children can decrease, for each client the number of increases has to be stored maybe: the increase/decrease messages affect a different counter than the number of clients see also -------- the mechanism of intercepting the time function calls with a preload library is based on that used by timeskew (https://github.com/vi/timeskew), which allows running a program on accelerated simulated time
About
run programs on a simulated time
Topics
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published