event-sched.c 30.1 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
/*
 * EMULAB-COPYRIGHT
Timothy Stack's avatar
   
Timothy Stack committed
3
 * Copyright (c) 2000-2005 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
4
5
6
 * All rights reserved.
 */

Ian Murdock's avatar
Ian Murdock committed
7
/*
8
 * event-sched.c --
Ian Murdock's avatar
Ian Murdock committed
9
10
11
 *
 *      Testbed event scheduler.
 *
12
13
14
15
16
 *      The event scheduler is an event system client; it operates by
 *      subscribing to the EVENT_SCHEDULE event, enqueuing the event
 *      notifications it receives, and resending the notifications at
 *      the indicated times.
 *
Ian Murdock's avatar
Ian Murdock committed
17
 */
Timothy Stack's avatar
   
Timothy Stack committed
18
19
20

#include "config.h"

Ian Murdock's avatar
Ian Murdock committed
21
#include <stdio.h>
Timothy Stack's avatar
   
Timothy Stack committed
22
#include <signal.h>
Ian Murdock's avatar
Ian Murdock committed
23
24
#include <sys/time.h>
#include <sys/types.h>
Timothy Stack's avatar
   
Timothy Stack committed
25
26
#include <sys/wait.h>
#include <sys/param.h>
Ian Murdock's avatar
Ian Murdock committed
27
28
#include <time.h>
#include <unistd.h>
29
30
#include <math.h>
#include <ctype.h>
Timothy Stack's avatar
   
Timothy Stack committed
31
32
33
34
35
#include <pwd.h>
#include <pthread.h>
#include <assert.h>
#include <paths.h>

36
#include "event-sched.h"
Timothy Stack's avatar
   
Timothy Stack committed
37
#include "error-record.h"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
38
#include "log.h"
39
#include "tbdefs.h"
40
#include "rpc.h"
41
#include "popenf.h"
Timothy Stack's avatar
   
Timothy Stack committed
42
43
44
45
46
47
48
49
50
#include "systemf.h"

#include "simulator-agent.h"
#include "group-agent.h"
#include "node-agent.h"
#include "timeline-agent.h"

#define EVENT_SCHED_PATH_ENV \
	"/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:" BINDIR ":" SBINDIR
Ian Murdock's avatar
Ian Murdock committed
51

52
static void enqueue(event_handle_t handle,
Timothy Stack's avatar
   
Timothy Stack committed
53
54
		    event_notification_t notification,
		    void *data);
55
static void dequeue(event_handle_t handle);
Timothy Stack's avatar
   
Timothy Stack committed
56
static int  handle_completeevent(event_handle_t handle, sched_event_t *eventp);
Ian Murdock's avatar
Ian Murdock committed
57

58
static char	*progname;
Timothy Stack's avatar
   
Timothy Stack committed
59
60
char	pideid[BUFSIZ];
char	*pid, *eid;
61
static int	get_static_events(event_handle_t handle);
Timothy Stack's avatar
   
Timothy Stack committed
62
int	debug;
Timothy Stack's avatar
   
Timothy Stack committed
63
const char *XMLRPC_ROOT = TBROOT;
Timothy Stack's avatar
   
Timothy Stack committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

struct lnList agents;

static struct lnList timelines;
static struct lnList sequences;
static struct lnList groups;

unsigned long next_token;

simulator_agent_t primary_simulator_agent;

static pid_t emcd_pid;
static pid_t vmcd_pid;
static pid_t rmcd_pid;

Timothy Stack's avatar
   
Timothy Stack committed
79
80
81
82
83
static struct agent ns_sequence_agent;
static timeline_agent_t ns_sequence;
static struct agent ns_timeline_agent;
static timeline_agent_t ns_timeline;

Timothy Stack's avatar
   
Timothy Stack committed
84
85
86
87
88
89
90
91
static void sigpass(int sig)
{
	kill(emcd_pid, sig);
	kill(vmcd_pid, sig);
	kill(rmcd_pid, sig);

	exit(0);
}
92

93
void
Timothy Stack's avatar
   
Timothy Stack committed
94
usage(void)
95
{
96
	fprintf(stderr,
Timothy Stack's avatar
   
Timothy Stack committed
97
98
99
100
101
102
103
104
		"Usage: %s [-hVd] [OPTIONS] <pid> <eid>\n"
		"\n"
		"Optional arguments:\n"
		"  -h          Print this message\n"
		"  -V          Print version information\n"
		"  -d          Turn on debugging\n"
		"  -s server   Specify location of elvind server. "
		"(Default: localhost)\n"
Timothy Stack's avatar
   
Timothy Stack committed
105
		"  -r          Use the standard RPC path. (Current: %s)\n"
Timothy Stack's avatar
   
Timothy Stack committed
106
107
108
109
110
111
112
		"  -p port     Specify port number of elvind server\n"
		"  -l logfile  Specify logfile to direct output\n"
		"  -k keyfile  Specify keyfile name\n"
		"\n"
		"Required arguments:\n"
		"  pid         The project ID of the experiment\n"
		"  eid         The experiment ID\n",
Timothy Stack's avatar
   
Timothy Stack committed
113
114
		progname,
		TBROOT);
115
116
117
	exit(-1);
}

Ian Murdock's avatar
Ian Murdock committed
118
int
Timothy Stack's avatar
   
Timothy Stack committed
119
main(int argc, char *argv[])
Ian Murdock's avatar
Ian Murdock committed
120
{
Leigh B. Stoller's avatar
Leigh B. Stoller committed
121
122
123
124
	address_tuple_t tuple;
	event_handle_t handle;
	char *server = NULL;
	char *port = NULL;
125
	char *log = NULL;
126
	char *keyfile = NULL;
Timothy Stack's avatar
   
Timothy Stack committed
127
	char buf[BUFSIZ];
128
	int c;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
129

Timothy Stack's avatar
   
Timothy Stack committed
130
131
132
133
	// sleep(600);

	setenv("PATH", EVENT_SCHED_PATH_ENV, 1);
	
134
135
	progname = argv[0];

Leigh B. Stoller's avatar
Leigh B. Stoller committed
136
137
138
	/* Initialize event queue semaphores: */
	sched_event_init();

Timothy Stack's avatar
   
Timothy Stack committed
139
140
141
142
143
	lnNewList(&agents);
	lnNewList(&timelines);
	lnNewList(&sequences);
	lnNewList(&groups);

Timothy Stack's avatar
   
Timothy Stack committed
144
	while ((c = getopt(argc, argv, "hVrs:p:dl:k:")) != -1) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
145
		switch (c) {
Timothy Stack's avatar
   
Timothy Stack committed
146
147
148
149
150
151
152
		case 'h':
			usage();
			break;
		case 'V':
			printf("%s\n", build_info);
			exit(0);
			break;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
153
		case 'd':
154
			debug++;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
155
			break;
Timothy Stack's avatar
   
Timothy Stack committed
156
157
158
		case 'r':
			XMLRPC_ROOT = "/usr/testbed";
			break;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
159
160
161
162
163
164
		case 's':
			server = optarg;
			break;
		case 'p':
			port = optarg;
			break;
165
166
167
		case 'l':
			log = optarg;
			break;
168
169
170
		case 'k':
			keyfile = optarg;
			break;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
171
		default:
Timothy Stack's avatar
   
Timothy Stack committed
172
173
			usage();
			break;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
174
175
176
177
		}
	}
	argc -= optind;
	argv += optind;
Ian Murdock's avatar
Ian Murdock committed
178

Timothy Stack's avatar
   
Timothy Stack committed
179
180
	if (argc != 2) {
		fprintf(stderr, "error: required arguments are missing.\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
181
		usage();
Timothy Stack's avatar
   
Timothy Stack committed
182
	}
183

Timothy Stack's avatar
   
Timothy Stack committed
184
185
186
	if (keyfile == NULL)
		keyfile = "tbdata/eventkey";
	
Leigh B. Stoller's avatar
Leigh B. Stoller committed
187
188
	pid = argv[0];
	eid = argv[1];
189
	sprintf(pideid, "%s/%s", pid, eid);
Ian Murdock's avatar
Ian Murdock committed
190

Timothy Stack's avatar
   
Timothy Stack committed
191
192
193
194
195
196
197
198
	if (RPC_init(NULL, BOSSNODE, 0)) {
		fatal("could not initialize rpc code");
	}

	if (RPC_grab()) {
		fatal("could not connect to rpc server");
	}
	
199
200
201
202
	setenv("LOGDIR", LOGDIR, 1);
	setenv("PID", pid, 1);
	setenv("EID", eid, 1);

Timothy Stack's avatar
   
Timothy Stack committed
203
204
205
206
	if (RPC_metadata(pid, eid)) {
		fatal("could not get experiment metadata");
	}

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
	/*
	 * Okay this is more complicated than it probably needs to be. We do
	 * not want to run anything on ops that is linked against the event
	 * system as root, even if its just to write out a pid file. This
	 * may be overly paranoid, but so be it. As a result, we do not
	 * want to use the usual daemon function, but rather depend on the
	 * caller (a perl script) to set the pid file then exec this
	 * program. The caller will also handle setting up stdout/stderr to
	 * write to the log file, and will close our stdin. The reason for
	 * writing the pid file in the caller is in order to kill the event
	 * scheduler, it must be done as root since the person swapping the
	 * experiment out might be different then the person who swapped it in
	 * (the scheduler runs as the person who swapped it in). Since the
	 * signal is sent as root, the pid file must not be in a place that
	 * is writable by mere user. 
	 */
	if (log)
224
		loginit(0, log);
225

Timothy Stack's avatar
   
Timothy Stack committed
226
227
228
	signal(SIGTERM, sigpass);
	signal(SIGINT, sigpass);
	signal(SIGQUIT, sigpass);
Ian Murdock's avatar
Ian Murdock committed
229

Leigh B. Stoller's avatar
Leigh B. Stoller committed
230
231
232
233
234
	/*
	 * Convert server/port to elvin thing.
	 *
	 * XXX This elvin string stuff should be moved down a layer. 
	 */
235
236
	if (!server)
		server = "localhost";
Timothy Stack's avatar
   
Timothy Stack committed
237

238
239
240
241
242
	snprintf(buf, sizeof(buf), "elvin://%s%s%s",
		 server,
		 (port ? ":"  : ""),
		 (port ? port : ""));
	server = buf;
Ian Murdock's avatar
Ian Murdock committed
243

Leigh B. Stoller's avatar
Leigh B. Stoller committed
244
	/* Register with the event system: */
245
	handle = event_register_withkeyfile(server, 1, keyfile);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
246
247
248
249
	if (handle == NULL) {
		fatal("could not register with event system");
	}

Timothy Stack's avatar
   
Timothy Stack committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
	ns_sequence = create_timeline_agent(TA_SEQUENCE);
	ns_sequence->ta_local_agent.la_link.ln_Name = ns_sequence_agent.name;
	ns_sequence->ta_local_agent.la_handle = handle;
	ns_sequence->ta_local_agent.la_agent = &ns_sequence_agent;
	ns_sequence_agent.link.ln_Name = ns_sequence_agent.name;
	strcpy(ns_sequence_agent.name, "__ns_sequence");
	strcpy(ns_sequence_agent.nodeid, "*");
	strcpy(ns_sequence_agent.vnode, "*");
	strcpy(ns_sequence_agent.objtype, TBDB_OBJECTTYPE_SEQUENCE);
	strcpy(ns_sequence_agent.ipaddr, "*");
	ns_sequence_agent.handler = &ns_sequence->ta_local_agent;
	lnAddTail(&sequences, &ns_sequence->ta_local_agent.la_link);
	lnAddTail(&agents, &ns_sequence_agent.link);
	
	ns_timeline = create_timeline_agent(TA_TIMELINE);
	ns_timeline->ta_local_agent.la_link.ln_Name = ns_timeline_agent.name;
	ns_timeline->ta_local_agent.la_handle = handle;
	ns_timeline->ta_local_agent.la_agent = &ns_timeline_agent;
	ns_timeline_agent.link.ln_Name = ns_timeline_agent.name;
	strcpy(ns_timeline_agent.name, "__ns_timeline");
	strcpy(ns_timeline_agent.nodeid, "*");
	strcpy(ns_timeline_agent.vnode, "*");
	strcpy(ns_timeline_agent.objtype, TBDB_OBJECTTYPE_TIMELINE);
	strcpy(ns_timeline_agent.ipaddr, "*");
	ns_timeline_agent.handler = &ns_timeline->ta_local_agent;
	lnAddTail(&timelines, &ns_timeline->ta_local_agent.la_link);
	lnAddTail(&agents, &ns_timeline_agent.link);

Leigh B. Stoller's avatar
Leigh B. Stoller committed
278
279
280
281
282
283
284
285
286
	/*
	 * Construct an address tuple for event subscription. We set the 
	 * scheduler flag to indicate we want to capture those notifications.
	 */
	tuple = address_tuple_alloc();
	if (tuple == NULL) {
		fatal("could not allocate an address tuple");
	}
	tuple->scheduler = 1;
287
	tuple->expt      = pideid;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
288
289
290
291
292

	if (event_subscribe(handle, enqueue, tuple, NULL) == NULL) {
		fatal("could not subscribe to EVENT_SCHEDULE event");
	}

Timothy Stack's avatar
   
Timothy Stack committed
293
294
295
296
297
298
	if (RPC_waitforactive(pid, eid))
		fatal("waitforactive: RPC failed!");

	if (RPC_agentlist(handle, pid, eid))
		fatal("Could not get agentlist from RPC server\n");

Timothy Stack's avatar
   
Timothy Stack committed
299
	if (RPC_waitforrobots(handle, pid, eid))
Timothy Stack's avatar
   
Timothy Stack committed
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
		fatal("waitforrobots: RPC failed!");

	if (access("tbdata/emcd.config", R_OK) == 0) {
	    char emc_path[256];

	    snprintf(emc_path,
		     sizeof(emc_path),
		     "%s/%s.%s.emcd",
		     _PATH_TMP,
		     pid,
		     eid);
	    
		emcd_pid = fork();
		switch (emcd_pid) {
		case -1:
			fatal("could not start emcd");
			break;
		case 0:
			execlp("emcd",
			       "emcd",
			       "-d",
			       "-l",
			       "logs/emcd.log",
			       "-c",
			       "tbdata/emcd.config",
			       "-e",
			       pideid,
			       "-U",
			       emc_path,
			       NULL);
			exit(0);
			break;
		default:
			break;
		}
		
		sleep(2);

Timothy Stack's avatar
   
Timothy Stack committed
338
339
		rmcd_pid = fork();
		switch (rmcd_pid) {
Timothy Stack's avatar
   
Timothy Stack committed
340
		case -1:
Timothy Stack's avatar
   
Timothy Stack committed
341
			fatal("could not start rmcd");
Timothy Stack's avatar
   
Timothy Stack committed
342
343
			break;
		case 0:
Timothy Stack's avatar
   
Timothy Stack committed
344
345
			execlp("rmcd",
			       "rmcd",
Timothy Stack's avatar
   
Timothy Stack committed
346
			       "-dd",
Timothy Stack's avatar
   
Timothy Stack committed
347
			       "-l",
Timothy Stack's avatar
   
Timothy Stack committed
348
			       "logs/rmcd.log",
Timothy Stack's avatar
   
Timothy Stack committed
349
350
351
352
353
354
355
356
357
358
359
			       "-U",
			       emc_path,
			       NULL);
			exit(0);
			break;
		default:
			break;
		}
		
		sleep(2);

Timothy Stack's avatar
   
Timothy Stack committed
360
361
362
#if 1
		vmcd_pid = fork();
		switch (vmcd_pid) {
Timothy Stack's avatar
   
Timothy Stack committed
363
		case -1:
Timothy Stack's avatar
   
Timothy Stack committed
364
			fatal("could not start vmcd");
Timothy Stack's avatar
   
Timothy Stack committed
365
366
			break;
		case 0:
Timothy Stack's avatar
   
Timothy Stack committed
367
368
			execlp("vmcd",
			       "vmcd",
Timothy Stack's avatar
   
Timothy Stack committed
369
370
			       "-d",
			       "-l",
Timothy Stack's avatar
   
Timothy Stack committed
371
			       "logs/vmcd.log",
Timothy Stack's avatar
   
Timothy Stack committed
372
373
374
375
376
377
378
379
			       "-U",
			       emc_path,
			       NULL);
			exit(0);
			break;
		default:
			break;
		}
Timothy Stack's avatar
   
Timothy Stack committed
380
381
382
383
#else
		systemf("vmcd -d -l logs/vmcd.log -e localhost -p 2626 "
			"-c junk.flux.utah.edu -P 6969 &");
#endif
Timothy Stack's avatar
   
Timothy Stack committed
384
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
385
386
387
388

	/*
	 * Read the static events list and schedule.
	 */
389
	if (get_static_events(handle) < 0) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
390
391
392
393
394
395
396
397
398
399
		fatal("could not get static event list");
	}

	/* Dequeue events and process them at the appropriate times: */
	dequeue(handle);

	/* Unregister with the event system: */
	if (event_unregister(handle) == 0) {
		fatal("could not unregister with event system");
	}
Ian Murdock's avatar
Ian Murdock committed
400

401
402
	info("Scheduler for %s/%s exiting\n", pid, eid);
	return 0;
Ian Murdock's avatar
Ian Murdock committed
403
404
}

Timothy Stack's avatar
   
Timothy Stack committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
int agent_invariant(struct agent *agent)
{
	assert(strlen(agent->name) > 0);
	assert(strlen(agent->vnode) > 0);
	assert(strlen(agent->objtype) > 0);
	if (agent->handler != NULL) // Don't know about this.
		assert(local_agent_invariant(agent->handler));
	
	return 1;
}

int sends_complete(struct agent *agent, const char *evtype)
{
	static char *run_completes[] = {
		TBDB_EVENTTYPE_RUN,
		NULL
	};

	static char *simulator_completes[] = {
		TBDB_EVENTTYPE_REPORT,
425
		TBDB_EVENTTYPE_MODIFY,
Timothy Stack's avatar
   
Timothy Stack committed
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
		NULL
	};

	static char *node_completes[] = {
		TBDB_EVENTTYPE_REBOOT,
		TBDB_EVENTTYPE_RELOAD,
		TBDB_EVENTTYPE_SETDEST,
		NULL
	};

	static struct {
		char *objtype;
		char **evtypes;
	} objtype2complete[] = {
		{ TBDB_OBJECTTYPE_LINK, NULL },
		{ TBDB_OBJECTTYPE_TRAFGEN, NULL },
		{ TBDB_OBJECTTYPE_TIME, NULL },
		{ TBDB_OBJECTTYPE_PROGRAM, run_completes },
		{ TBDB_OBJECTTYPE_SIMULATOR, simulator_completes },
		{ TBDB_OBJECTTYPE_LINKTEST, NULL },
		{ TBDB_OBJECTTYPE_NSE, NULL },
		{ TBDB_OBJECTTYPE_CANARYD, NULL },
448
		{ "SLOTHD", NULL }, // XXX
Timothy Stack's avatar
   
Timothy Stack committed
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
		{ TBDB_OBJECTTYPE_NODE, node_completes },
		{ TBDB_OBJECTTYPE_TIMELINE, run_completes },
		{ TBDB_OBJECTTYPE_SEQUENCE, run_completes },
		{ NULL, NULL }
	};

	const char *objtype;
	int lpc, retval = 0;
	
	assert(agent != NULL);
	assert(evtype != NULL);

	if (strcmp(agent->objtype, TBDB_OBJECTTYPE_GROUP) == 0) {
		group_agent_t ga = (group_agent_t)agent->handler;
		
		objtype = ga->ga_agents[1]->objtype;
	}
	else {
		objtype = agent->objtype;
	}
	
	for (lpc = 0; objtype2complete[lpc].objtype != NULL; lpc++ ) {
		if (strcmp(objtype2complete[lpc].objtype, objtype) == 0) {
			char **ec;
			
			if ((ec = objtype2complete[lpc].evtypes) == NULL) {
				retval = 0;
				break;
			}
			else {
				int lpc2;

				retval = 0;
				for (lpc2 = 0; ec[lpc2] != NULL; lpc2++) {
					if (strcmp(ec[lpc2], evtype) == 0) {
						retval = 1;
						break;
					}
				}
				break;
			}
		}
	}

	if (objtype2complete[lpc].objtype == NULL) {
		error("Unknown object type %s\n", objtype);
		assert(0);
	}

	return retval;
}

int
sched_event_prepare(event_handle_t handle, sched_event_t *se)
{
	int retval;

506
507
508
509
510
	if (se->agent.s == NULL) {
		event_notification_insert_hmac(handle, se->notification);
		return 0;
	}
	
Timothy Stack's avatar
   
Timothy Stack committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
	assert(se != NULL);
	assert(se->length == 1);

	if ((se->agent.s->handler != NULL) &&
	    (se->agent.s->handler->la_expand != NULL)) {
		local_agent_t la = se->agent.s->handler;

		retval = la->la_expand(la, se);
	}
	else {
		event_notification_clear_objtype(handle, se->notification);
		event_notification_set_objtype(handle,
					       se->notification,
					       se->agent.s->objtype);
		event_notification_insert_hmac(handle, se->notification);

		retval = 0;
	}
	
	return retval;
}

533
/* Enqueue event notifications as they arrive. */
Ian Murdock's avatar
Ian Murdock committed
534
static void
535
enqueue(event_handle_t handle, event_notification_t notification, void *data)
Ian Murdock's avatar
Ian Murdock committed
536
{
Timothy Stack's avatar
   
Timothy Stack committed
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
	sched_event_t		event;
	char			objname[TBDB_FLEN_EVOBJNAME];
	char			timeline[TBDB_FLEN_EVOBJNAME] = "";
	char			eventtype[TBDB_FLEN_EVEVENTTYPE];
	struct agent	       *agentp;
	timeline_agent_t	ta = NULL;
	
	if (! event_notification_get_timeline(handle, notification,
						   timeline,
						   sizeof(timeline))) {
		warning("could not get timeline?\n");
		/* Not fatal since we have to deal with legacy systems. */
	}
	
	/* Get the event's firing time: */
	if (! event_notification_get_int32(handle, notification, "time_usec",
					   (int *) &event.time.tv_usec) ||
	    ! event_notification_get_int32(handle, notification, "time_sec",
					   (int *) &event.time.tv_sec)) {
		error("could not get time from notification %p\n",
		      notification);
	}
	else if (! event_notification_get_objname(handle, notification,
						  objname, sizeof(objname))) {
		error("could not get object name from notification %p\n",
		      notification);
	}
	else if (! event_notification_get_eventtype(handle, notification,
						    eventtype,
						    sizeof(eventtype))) {
		error("could not get event type from notification %p\n",
		      notification);
	}
	else  if ((agentp = (struct agent *)
		   lnFindName(&agents, objname)) == NULL) {
		error("%s\n", eventtype);
		error("Could not map object to an agent: %s\n", objname);
	}
	else if ((strlen(timeline) > 0) &&
		 (strcmp(timeline, ADDRESSTUPLE_ALL) != 0) &&
		 ((ta = (timeline_agent_t)
		   lnFindName(&timelines, timeline)) == NULL) &&
		 ((ta = (timeline_agent_t)
		   lnFindName(&sequences, timeline)) == NULL)) {
		error("Unknown timeline: %s\n", timeline);
	}
	else {
		event.agent.s = agentp;
		event.length = 1;
		event.flags = SEF_SINGLE_HANDLER;
		
		/*
		 * Clone the event notification, since we want the
		 * notification to live beyond the callback function:
		 */
		event.notification =
			event_notification_clone(handle, notification);
		
		if (!event.notification) {
			error("event_notification_clone failed!\n");
			return;
		}
		
		/*
		 * Clear the scheduler flag. Not allowed to do this above
		 * the loop cause the notification thats comes in is
		 * "read-only".
		 */
		if (! event_notification_remove(handle,
Leigh B. Stoller's avatar
Leigh B. Stoller committed
606
						event.notification,
Timothy Stack's avatar
   
Timothy Stack committed
607
608
						"SCHEDULER") ||
		    ! event_notification_put_int32(handle,
Leigh B. Stoller's avatar
Leigh B. Stoller committed
609
						   event.notification,
Timothy Stack's avatar
   
Timothy Stack committed
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
						   "SCHEDULER",
						   0)) {
			error("could not clear scheduler attribute of "
			      "notification %p\n", event.notification);
			return;
		}
		
		if (debug) {
			struct timeval now;
		    
			gettimeofday(&now, NULL);
			
			info("Sched: "
			     "note:%p at:%ld:%d now:%ld:%d agent:%s %s\n",
			     event.notification,
			     event.time.tv_sec, event.time.tv_usec,
			     now.tv_sec, now.tv_usec, agentp->name,
			     eventtype);
		}
		
		if (strcmp(eventtype, TBDB_EVENTTYPE_COMPLETE) == 0) {
			event.flags |= SEF_COMPLETE_EVENT;
			sched_event_enqueue(event);
			return;
		}
Timothy Stack's avatar
   
Timothy Stack committed
635

Timothy Stack's avatar
   
Timothy Stack committed
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
		if (sends_complete(agentp, eventtype))
			event.flags |= SEF_SENDS_COMPLETE;
		
		event_notification_clear_host(handle, event.notification);
		event_notification_set_host(handle,
					    event.notification,
					    agentp->ipaddr);
		event_notification_put_int32(handle,
					     event.notification,
					     "TOKEN",
					     next_token);
		next_token += 1;
		
		/*
		 * Enqueue the event notification for resending at the
		 * indicated time:
		 */
		sched_event_prepare(handle, &event);
		if (ta != NULL)
			timeline_agent_append(ta, &event);
		else
			sched_event_enqueue(event);
	}
659
660
661
}

static void
Timothy Stack's avatar
   
Timothy Stack committed
662
handle_event(event_handle_t handle, sched_event_t *se)
663
{
Timothy Stack's avatar
   
Timothy Stack committed
664
665
666
	assert(handle != NULL);
	assert(se != NULL);
	assert(se->length == 1);
667

Timothy Stack's avatar
   
Timothy Stack committed
668
669
670
	if ((se->agent.s != NULL) &&
	    (se->agent.s->handler != NULL)) {
		local_agent_queue(se->agent.s->handler, se);
671
	}
Timothy Stack's avatar
   
Timothy Stack committed
672
673
	else if (event_notify(handle, se->notification) == 0) {
		error("could not fire event\n");
674
675
		return;
	}
Timothy Stack's avatar
   
Timothy Stack committed
676
	else if (se->flags & SEF_TIME_START) {
677
678
679
680
681
682
		static int did_start = 0;

		if (!did_start) {
			RPC_notifystart(pid, eid, "", 1);
			RPC_drop();
		}
Timothy Stack's avatar
   
Timothy Stack committed
683
	}
Timothy Stack's avatar
   
Timothy Stack committed
684
}
685

Timothy Stack's avatar
   
Timothy Stack committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
/* Dequeue events from the event queue and fire them at the
   appropriate time.  Runs in a separate thread. */
static void
dequeue(event_handle_t handle)
{
	sched_event_t next_event;
	struct timeval now;
	
	while (1) {
		if (sched_event_dequeue(&next_event, 1) < 0)
			break;
		
		/* Fire event. */
		if (debug)
			gettimeofday(&now, NULL);

		if (debug) {
			info("Fire:  note:%p at:%ld:%d now:%ld:%d agent:%s\n",
			     next_event.notification,
			     next_event.time.tv_sec, next_event.time.tv_usec,
			     now.tv_sec,
			     now.tv_usec,
			     next_event.agent.s ?
			     (next_event.length == 1 ?
			      next_event.agent.s->name :
			      next_event.agent.m[0]->name) : "*");
		}
		
		if (next_event.flags & SEF_COMPLETE_EVENT) {
			assert(next_event.length == 1);
			
			handle_completeevent(handle, &next_event);
		}
		else if (next_event.length == 1) {
			handle_event(handle, &next_event);
		}
		else if ((next_event.flags & SEF_SINGLE_HANDLER) &&
			 (next_event.agent.m[0]->handler != NULL)) {
			local_agent_queue(next_event.agent.m[0]->handler,
					  &next_event);
		}
		else {
			sched_event_t se_tmp;
			int lpc;

			se_tmp = next_event;
			se_tmp.length = 1;
			for (lpc = 0; lpc < next_event.length; lpc++) {
				se_tmp.agent.s = next_event.agent.m[lpc];
				handle_event(handle, &se_tmp);
			}
		}

		sched_event_free(handle, &next_event);
	}
Ian Murdock's avatar
Ian Murdock committed
741
}
Timothy Stack's avatar
   
Timothy Stack committed
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779

int
SetExpPath(const char *path)
{
	setenv("EXPDIR", path, 1);
	return chdir(path);
}

int
AddUserEnv(char *name, char *path)
{
	int retval = 0;
	FILE *file;
	
	/* XXX Kind of a stupid way to eval any variables. */
	if ((file = popenf("echo %s=%s", "r", name, path)) == NULL) {
		retval = -1;
	}
	else {
		char buf[BUFSIZ];
		
		if (fgets(buf, sizeof(buf), file) != NULL) {
			char *idx;
			
			if ((idx = strchr(buf, '\n')) != NULL)
				*idx = '\0';
			if ((idx = strchr(buf, '=')) != NULL) {
				*idx = '\0';
				retval = setenv(strdup(buf), idx + 1, 1);
			}
		}
		pclose(file);
		file = NULL;
	}
	
	return 0;
}

780
781
782
783
784
785
786
/*
 * Stuff to get the event list.
 */
/*
 * Add an agent to the list.
 */
int
Timothy Stack's avatar
   
Timothy Stack committed
787
788
AddAgent(event_handle_t handle,
	 char *vname, char *vnode, char *nodeid, char *ipaddr, char *type)
789
790
{
	struct agent *agentp;
Timothy Stack's avatar
   
Timothy Stack committed
791
		
792
793
794
795
796
	if ((agentp = calloc(sizeof(struct agent), 1)) == NULL) {
		error("AddAgent: Out of memory\n");
		return -1;
	}

Timothy Stack's avatar
   
Timothy Stack committed
797
798
799
800
	strcpy(agentp->name, vname);
	agentp->link.ln_Name = agentp->name;
	
	strcpy(agentp->vnode, vnode);
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
	strcpy(agentp->objtype, type);

	/*
	 * Look for a wildcard in the vnode slot. As a result
	 * the node_id will come back null from the reserved
	 * table.
	 */
	if (strcmp("*", vnode)) {
		/*
		 * Event goes to specific node.
		 */
		strcpy(agentp->nodeid, nodeid);
		strcpy(agentp->ipaddr, ipaddr);
	}
	else {
		/*
		 * Force events to all nodes. The agents will
		 * need to discriminate on stuff inside the event.
		 */
		strcpy(agentp->nodeid, ADDRESSTUPLE_ALL);
		strcpy(agentp->ipaddr, ADDRESSTUPLE_ALL);
	}
Timothy Stack's avatar
   
Timothy Stack committed
823
824
825
826
827
828
829
830
831
832
833
	
	if (strcmp(type, TBDB_OBJECTTYPE_SIMULATOR) == 0) {
		if ((primary_simulator_agent =
		     create_simulator_agent()) != NULL) {
			primary_simulator_agent->sa_local_agent.la_link.
				ln_Name = agentp->name;
			primary_simulator_agent->sa_local_agent.la_agent =
			    agentp;
			agentp->handler = &primary_simulator_agent->
				sa_local_agent;
		}
834
	}
Timothy Stack's avatar
   
Timothy Stack committed
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
	else if ((strcmp(type, TBDB_OBJECTTYPE_TIMELINE) == 0) ||
		 (strcmp(type, TBDB_OBJECTTYPE_SEQUENCE) == 0)) {
		timeline_agent_t ta;
		ta_kind_t tk;

		tk = strcmp(type, TBDB_OBJECTTYPE_TIMELINE) == 0 ?
			TA_TIMELINE : TA_SEQUENCE;
		if ((ta = create_timeline_agent(tk)) != NULL) {
			switch (tk) {
			case TA_TIMELINE:
				lnAddTail(&timelines,
					  &ta->ta_local_agent.la_link);
				break;
			case TA_SEQUENCE:
				lnAddTail(&sequences,
					  &ta->ta_local_agent.la_link);
				break;
			default:
				assert(0);
				break;
			}
			ta->ta_local_agent.la_link.ln_Name = agentp->name;
			ta->ta_local_agent.la_agent = agentp;
			agentp->handler = &ta->ta_local_agent;
		}
860
	}
Timothy Stack's avatar
   
Timothy Stack committed
861
862
863
864
865
866
867
868
869
	else if (strcmp(type, TBDB_OBJECTTYPE_NODE) == 0) {
		node_agent_t na;
		
		if ((na = create_node_agent()) == NULL) {
		}
		else {
			na->na_local_agent.la_agent = agentp;
			agentp->handler = &na->na_local_agent;
		}
870
871
	}

Timothy Stack's avatar
   
Timothy Stack committed
872
873
874
875
876
877
878
879
	if (agentp->handler != NULL) {
		agentp->handler->la_handle = handle;
	}
	
	assert(agent_invariant(agentp));
	assert(lnFindName(&agents, vname) == NULL);
	
	lnAddTail(&agents, &agentp->link);
880
881
882
883
884

	return 0;
}

/*
Timothy Stack's avatar
   
Timothy Stack committed
885
 * Add an agent group to the list.
886
 */
Timothy Stack's avatar
   
Timothy Stack committed
887
888
int
AddGroup(event_handle_t handle, char *groupname, char *agentname)
889
{
Timothy Stack's avatar
   
Timothy Stack committed
890
891
	struct agent *group = NULL, *agent;
	int retval = 0;
892

Timothy Stack's avatar
   
Timothy Stack committed
893
894
895
896
	assert(groupname != NULL);
	assert(strlen(groupname) > 0);
	assert(agentname != NULL);
	assert(strlen(agentname) > 0);
897

Timothy Stack's avatar
   
Timothy Stack committed
898
899
	if ((agent = (struct agent *)lnFindName(&agents, agentname)) == NULL) {
		error("unknown agent %s\n", agentname);
900
		
Timothy Stack's avatar
   
Timothy Stack committed
901
902
903
904
905
		retval = -1;
	}
	else if ((group = (struct agent *)lnFindName(&agents,
						     groupname)) == NULL) {
		group_agent_t ga;
906

Timothy Stack's avatar
   
Timothy Stack committed
907
908
909
		if ((group = calloc(sizeof(struct agent), 1)) == NULL) {
			// XXX delete_group_agent
			error("out of memory\n");
910
			
Timothy Stack's avatar
   
Timothy Stack committed
911
			retval = -1;
912
		}
Timothy Stack's avatar
   
Timothy Stack committed
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
		else if ((ga = create_group_agent(group)) == NULL) {
			errorc("cannot create group agent\n");
			
			free(group);
			group = NULL;
			
			retval = -1;
		}
		else {
			ga->ga_local_agent.la_handle = handle;
			
			strcpy(group->name, groupname);
			group->link.ln_Name = group->name;
			strcpy(group->nodeid, ADDRESSTUPLE_ALL);
			strcpy(group->vnode, ADDRESSTUPLE_ALL);
			strcpy(group->objtype, TBDB_OBJECTTYPE_GROUP);
			strcpy(group->ipaddr, ADDRESSTUPLE_ALL);
			group->handler = &ga->ga_local_agent;
			
			lnAddTail(&agents, &group->link);
			lnAddTail(&groups, &ga->ga_local_agent.la_link);
			
			assert(agent_invariant(group));
936
937
		}
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
938

Timothy Stack's avatar
   
Timothy Stack committed
939
940
941
942
943
944
	if (retval == 0) {
		group_agent_t ga;
		
		ga = (group_agent_t)group->handler;
		if ((retval = group_agent_append(ga, agent)) < 0) {
			errorc("cannot append agent to group\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
945
		}
946
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
947

Timothy Stack's avatar
   
Timothy Stack committed
948
	return retval;
949
950
951
952
953
}

int
AddEvent(event_handle_t handle, address_tuple_t tuple, long basetime,
	 char *exidx, char *ftime, char *objname, char *exargs,
Timothy Stack's avatar
   
Timothy Stack committed
954
	 char *objtype, char *evttype, char *parent)
955
{
Timothy Stack's avatar
   
Timothy Stack committed
956
	timeline_agent_t     ta = NULL;
957
958
	sched_event_t	     event;
	double		     firetime = atof(ftime);
959
	struct agent	    *agentp = NULL;
960
961
	struct timeval	     time;

962
963
964
965
	if (strcmp(objtype, TBDB_OBJECTTYPE_TIME) == 0) {
		return 0;
	}

Timothy Stack's avatar
   
Timothy Stack committed
966
	if ((agentp = (struct agent *)lnFindName(&agents, objname)) == NULL) {
967
968
969
970
		error("AddEvent: Could not map event index %s\n", exidx);
		return -1;
	}

Timothy Stack's avatar
   
Timothy Stack committed
971
972
973
974
975
976
977
978
979
	if (parent && strlen(parent) > 0) {
		if (((ta = (timeline_agent_t)lnFindName(&timelines,
							parent)) == NULL) &&
		    ((ta = (timeline_agent_t)lnFindName(&sequences,
							parent)) == NULL)) {
			error("AddEvent: Could not map parent %s\n", parent);
			return -1;
		}
	}
Timothy Stack's avatar
   
Timothy Stack committed
980
981
982
	else {
		ta = ns_timeline;
	}
Timothy Stack's avatar
   
Timothy Stack committed
983
	
984
985
986
987
988
	tuple->host      = agentp->ipaddr;
	tuple->objname   = objname;
	tuple->objtype   = objtype;
	tuple->eventtype = evttype;

Timothy Stack's avatar
   
Timothy Stack committed
989
	memset(&event, 0, sizeof(event));
990
991
992
993
994
995
996
	event.notification = event_notification_alloc(handle, tuple);
	if (! event.notification) {
		error("AddEvent: could not allocate notification\n");
		return -1;
	}
	event_notification_set_arguments(handle, event.notification, exargs);

997
	if (debug)
Timothy Stack's avatar
   
Timothy Stack committed
998
999
1000
1001
1002
1003
1004
		info("%8s %10s %10s %10s %10s %10s %s %p\n",
		     ftime, objname, objtype,
		     evttype, agentp->ipaddr, 
		     exargs ? exargs : "",
		     parent,
		     event.notification);

1005
1006
	event_notification_insert_hmac(handle, event.notification);

Timothy Stack's avatar
   
Timothy Stack committed
1007
1008
	time.tv_sec  = (int)firetime;
	time.tv_usec = (int)((firetime - (floor(firetime))) * 1000000);
1009
1010
1011
1012
	if (time.tv_usec >= 1000000) {
		time.tv_sec  += 1;
		time.tv_usec -= 1000000;
	}
Timothy Stack's avatar
   
Timothy Stack committed
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
	if (ta == NULL) {
		time.tv_sec  += basetime;
	}
	event.time = time;
	event.agent.s = agentp;
	event.length = 1;
	event.flags = SEF_SINGLE_HANDLER;
	if (sends_complete(agentp, evttype))
		event.flags |= SEF_SENDS_COMPLETE;
	event_notification_put_int32(handle,
				     event.notification,
				     "TOKEN",
				     next_token);
	next_token += 1;
	
	sched_event_prepare(handle, &event);
	if (ta != NULL)
		timeline_agent_append(ta, &event);
	else
		sched_event_enqueue(event);
	
1034
1035
1036
	return 0;
}

Timothy Stack's avatar
   
Timothy Stack committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
int
AddRobot(event_handle_t handle,
	 struct agent *agent,
	 double init_x,
	 double init_y,
	 double init_o)
{
	sched_event_t se;
	int retval = 0;

	assert(agent != NULL);

	se.agent.s = agent;
	se.notification = event_notification_create(
		handle,
		EA_Experiment, pideid,
		EA_Type, TBDB_OBJECTTYPE_NODE,
		EA_Event, TBDB_EVENTTYPE_SETDEST,
		EA_Name, agent->name,
		EA_ArgFloat, "X", init_x,
		EA_ArgFloat, "Y", init_y,
		EA_ArgFloat, "ORIENTATION", init_o,
		EA_TAG_DONE);
	event_notification_put_int32(handle,
				     se.notification,
				     "TOKEN",
				     next_token);
	next_token += 1;
	
	memset(&se.time, 0, sizeof(se.time));
	se.length = 1;
	se.flags = SEF_SENDS_COMPLETE | SEF_SINGLE_HANDLER;
	
	sched_event_prepare(handle, &se);
	timeline_agent_append(ns_sequence, &se);
	
	return retval;
}

1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
/*
 * Get the static event list from the DB and schedule according to
 * the relative time stamps.
 */
static int
get_static_events(event_handle_t handle)
{
	struct timeval	now;
	long            basetime;
	address_tuple_t tuple;
	event_notification_t notification;
	sched_event_t	event;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1088

1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
	/*
	 * Construct an address tuple for the notifications. We can reuse
	 * the same one over and over since the data is copied out.
	 */
	tuple = address_tuple_alloc();
	if (tuple == NULL) {
		error("could not allocate an address tuple\n");
		return -1;
	}
	tuple->expt = pideid;

1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
	/*
	 * Generate a TIME starts message.
	 */
	tuple->host      = ADDRESSTUPLE_ALL;
	tuple->objname   = ADDRESSTUPLE_ANY;
	tuple->objtype   = TBDB_OBJECTTYPE_TIME;
	tuple->eventtype = TBDB_EVENTTYPE_START;
	
	notification = event_notification_alloc(handle, tuple);
	if (! notification) {
1110
1111
		error("could not allocate notification\n");
		return -1;
1112
	}
1113
	event_notification_insert_hmac(handle, notification);
1114
	event.notification = notification;
Timothy Stack's avatar
   
Timothy Stack committed
1115
	event.time.tv_sec  = 0;
1116
	event.time.tv_usec = 0;
Timothy Stack's avatar
   
Timothy Stack committed
1117
1118
	event.agent.s = NULL;
	event.length = 1;
Timothy Stack's avatar
   
Timothy Stack committed
1119
	event.flags = SEF_TIME_START;
Timothy Stack's avatar
   
Timothy Stack committed
1120
1121
1122
1123
1124
1125
1126
1127
	timeline_agent_append(ns_sequence, &event);

	
	event.agent.s = primary_simulator_agent->sa_local_agent.la_agent;
	event.notification = event_notification_create(
		handle,
		EA_Experiment, pideid,
		EA_Type, TBDB_OBJECTTYPE_SIMULATOR,
1128
		EA_Event, TBDB_EVENTTYPE_DEBUG,
Timothy Stack's avatar
   
Timothy Stack committed
1129
1130
1131
1132
1133
1134
1135
1136
1137
		EA_Name, event.agent.s->name,
		EA_Arguments, "Time started",
		EA_TAG_DONE);
	memset(&event.time, 0, sizeof(event.time));
	event.length = 1;
	event.flags = SEF_SINGLE_HANDLER;
	
	sched_event_prepare(handle, &event);
	timeline_agent_append(ns_sequence, &event);
1138

Timothy Stack's avatar
   
Timothy Stack committed
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
	
	event.agent.s = &ns_timeline_agent;
	event.notification = event_notification_create(
		handle,
		EA_Experiment, pideid,
		EA_Type, TBDB_OBJECTTYPE_TIMELINE,
		EA_Event, TBDB_EVENTTYPE_START,
		EA_Name, ns_timeline_agent.name,
		EA_TAG_DONE);
	memset(&event.time, 0, sizeof(event.time));
	event.length = 1;
	event.flags = SEF_SENDS_COMPLETE | SEF_SINGLE_HANDLER;
	
	sched_event_prepare(handle, &event);
	timeline_agent_append(ns_sequence, &event);

	if (RPC_grouplist(handle, pid, eid)) {
		error("Could not get grouplist from RPC server\n");
		return -1;
	}
	
	if (debug) {
		struct agent *agentp = (struct agent *)agents.lh_Head;
1162

Timothy Stack's avatar
   
Timothy Stack committed
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
		while (agentp->link.ln_Succ) {
			info("Agent: %15s  %10s %10s %8s %16s\n",
			     agentp->name, agentp->objtype,
			     agentp->vnode, agentp->nodeid,
			     agentp->ipaddr);

			agentp = (struct agent *)agentp->link.ln_Succ;
		}
	}

	sprintf(pideid, "%s/%s", pid, eid);
1174
	gettimeofday(&now, NULL);
Timothy Stack's avatar
   
Timothy Stack committed
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
	info(" Getting event stream at: %lu:%d\n",  now.tv_sec, now.tv_usec);
	
	/*
	 * XXX Pad the start time out a bit to give this code a chance to run.
	 */
	basetime = now.tv_sec + 3;
	
	if (RPC_eventlist(pid, eid, handle, tuple, basetime)) {
		error("Could not get eventlist from RPC server\n");
		return -1;
	}
1186

Timothy Stack's avatar
   
Timothy Stack committed
1187
1188
1189
1190
1191
1192
1193
	event_do(handle,
		 EA_Experiment, pideid,
		 EA_Type, TBDB_OBJECTTYPE_SEQUENCE,
		 EA_Event, TBDB_EVENTTYPE_START,
		 EA_Name, ns_sequence_agent.name,
		 EA_TAG_DONE);
	
1194
	return 0;
1195
}
Timothy Stack's avatar
   
Timothy Stack committed
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214

int
sched_event_enqueue_copy(event_handle_t handle,
			 sched_event_t *se,
			 struct timeval *new_time)
{
	sched_event_t se_copy = *se;
	int retval = 0;

	assert(handle != NULL);
	assert(se != NULL);
	assert(se->length > 0);
	assert(new_time != NULL);

	se_copy.notification =
		event_notification_clone(handle, se->notification);
	if (new_time != NULL)
		se_copy.time = *new_time;
	sched_event_enqueue(se_copy);
1215
	
Timothy Stack's avatar
   
Timothy Stack committed
1216
1217
1218
1219
1220
	return retval;
}

void
sched_event_free(event_handle_t handle, sched_event_t *se)
1221
{
Timothy Stack's avatar
   
Timothy Stack committed
1222
1223
	assert(handle != NULL);
	assert(se != NULL);
1224

Timothy Stack's avatar
   
Timothy Stack committed
1225
	if (se->length == 0) {
1226
	}
Timothy Stack's avatar
   
Timothy Stack committed
1227
1228
1229
	else {
		event_notification_free(handle, se->notification);
		se->notification = NULL;
1230
1231
	}
}
1232

Timothy Stack's avatar
   
Timothy Stack committed
1233
1234
static int
handle_completeevent(event_handle_t handle, sched_event_t *eventp)
1235
{
Timothy Stack's avatar
   
Timothy Stack committed
1236
1237
	char *value, argsbuf[BUFSIZ] = "";
	char objname[TBDB_FLEN_EVOBJNAME];
Timothy Stack's avatar
   
Timothy Stack committed
1238
	char objtype[TBDB_FLEN_EVOBJTYPE];
Timothy Stack's avatar
   
Timothy Stack committed
1239
	int rc, ctoken = ~0, agerror = 0;
1240
	
Timothy Stack's avatar
   
Timothy Stack committed
1241
1242
	event_notification_get_objname(handle, eventp->notification,
				       objname, sizeof(objname));
1243

Timothy Stack's avatar
   
Timothy Stack committed
1244
1245
1246
	event_notification_get_objtype(handle, eventp->notification,
				       objtype, sizeof(objtype));

Timothy Stack's avatar
   
Timothy Stack committed
1247
1248
1249
1250
1251
1252
	event_notification_get_arguments(handle, eventp->notification,
					 argsbuf, sizeof(argsbuf));
	
	if ((rc = event_arg_get(argsbuf, "ERROR", &value)) > 0) {
		if (sscanf(value, "%d", &agerror) != 1) {
			error("bad error value for complete: %s\n", argsbuf);
1253
		}
Timothy Stack's avatar
   
Timothy Stack committed
1254
1255
1256
1257
1258
1259
1260
1261
	}
	else {
		warning("completion event is missing ERROR argument\n");
	}
	
	if ((rc = event_arg_get(argsbuf, "CTOKEN", &value)) > 0) {
		if (sscanf(value, "%d", &ctoken) != 1) {
			error("bad ctoken value for complete: %s\n", argsbuf);
1262
		}
Timothy Stack's avatar
   
Timothy Stack committed
1263
1264
1265
1266
	}
	else {
		warning("completion event is missing CTOKEN argument\n");
	}
1267

Timothy Stack's avatar
   
Timothy Stack committed
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
	if (agerror != 0) {
		error_record_t er;
		
		if ((er = create_error_record()) == NULL) {
			errorc("could not allocate error record");
		}
		else {
			er->er_agent = eventp->agent.s;
			er->er_token = ctoken;
			er->er_error = agerror;
			lnAddTail(&primary_simulator_agent->sa_error_records,
				  &er->er_link);
		}
1281
1282
	}

Timothy Stack's avatar
   
Timothy Stack committed
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
	sequence_agent_handle_complete(handle,
				       &sequences,
				       eventp->agent.s,
				       ctoken,
				       agerror);

	group_agent_handle_complete(handle,
				    &groups,
				    eventp->agent.s,
				    ctoken,
				    agerror);
Timothy Stack's avatar
   
Timothy Stack committed
1294

1295
1296
	if ((strcmp(objtype, TBDB_OBJECTTYPE_TIMELINE) == 0) ||
	    (strcmp(objtype, TBDB_OBJECTTYPE_SEQUENCE) == 0)) {
Timothy Stack's avatar
   
Timothy Stack committed
1297
1298
1299
1300
		RPC_grab();
		RPC_notifystart(pid, eid, objname, 0);
		RPC_drop();
	}
Timothy Stack's avatar
   
Timothy Stack committed
1301
1302
	
	return 1;
1303
}