Don't create thread at start
[nativeclient.git] / service_runtime / sel_universal.c
blob86a13870cfb9b3f671bcb678a8b6d74a6363d6fa
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl testing shell
36 #include "native_client/include/portability.h"
37 #include "native_client/intermodule_comm/nacl_imc_c.h"
38 #include "native_client/nonnacl_util/sel_ldr_launcher_c.h"
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <sys/types.h>
44 #include <signal.h>
46 #if NACL_WINDOWS
47 #include <process.h>
48 static int gettimeofday(struct timeval *tv, struct timezone *tz);
49 #else
50 #include <sys/time.h>
51 #include <sys/wait.h>
52 #include <unistd.h>
53 #endif
55 #include "native_client/service_runtime/nacl_check.h"
56 #include "native_client/tools/libsrpc/nacl_srpc.h"
58 #define MAX_ARRAY_SIZE 4096
59 #define MAX_COMMAND_LINE_ARGS 256
60 #define SEL_LDR_CMD_LINE_EXEC_POS 4
62 #if NACL_WINDOWS
63 static char* kSelLdrPathname = "/usr/local/nacl-sdk/nacl/bin/sel_ldr.exe";
64 #else
65 static char* kSelLdrPathname = "/usr/local/nacl-sdk/nacl/bin/sel_ldr";
66 #endif
68 static char* g_sel_ldr_pathname;
70 static int timed_rpc_count;
71 static uint32_t timed_rpc_method = 1;
72 static int timed_rpc_bytes = 4000;
74 void blackhole(char *s, ...) {}
75 /* #define DEBUG printf */
76 #define DEBUG blackhole
78 /* simple destructive tokenizer */
79 typedef struct {
80 const char* start;
81 int length;
82 } TOKEN;
84 /* expects *from to point to leading \" and returns pointer to trailing \" */
85 const char* ScanEscapeString(char* to, const char* from) {
86 CHECK(*from == '\"');
87 from++;
88 while (*from) {
89 if (*from == '\"') {
90 if (to) *to = '\0';
91 return from;
92 }else if (*from != '\\') {
93 if (to) *to++ = *from;
94 from++;
95 } else {
96 char next = *from++;
97 switch(next) {
98 case '\0':
99 return 0;
100 case '\\':
101 case '\"':
102 if (to) *to++ = next;
103 break;
104 case 'n':
105 if (to) *to++ = '\n';
106 break;
107 default:
108 return 0;
112 return 0;
115 int Tokenize(char* line, TOKEN *array, int n) {
116 int pos_start = 0;
117 int count = 0;
119 for( ; count < n; count++ ) {
120 int pos_end;
122 /* skip leading white space */
123 while (line[pos_start]) {
124 const char c = line[pos_start];
125 if (isspace(c)) {
126 pos_start++;
127 } else {
128 break;
132 if (!line[pos_start]) break;
134 /* find token end from current pos_start */
135 pos_end = pos_start;
137 while (line[pos_end]) {
138 const char c = line[pos_end];
140 if (isspace(c)) {
141 break;
142 } else if (c == '\"') {
143 const char* end = ScanEscapeString(0, &line[pos_end]);
144 if (!end) return -1;
145 pos_end = end - &line[0];
147 pos_end++;
150 /* save the token */
151 array[count].start = &line[pos_start];
152 array[count].length = pos_end - pos_start;
154 if (line[pos_end]) {
155 line[pos_end] = '\0'; /* DESTRUCTION!!! */
156 pos_end++;
158 pos_start = pos_end;
159 /* printf("TOKEN %s\n", array[count].start); */
162 return count;
165 /* NOTE: This is leaking memory left and right */
166 int ParseArg(NaClSrpcArg* arg, const char* token) {
167 long val;
168 int dim;
169 const char* comma;
170 int i;
172 DEBUG("TOKEN %s\n", token);
173 CHECK(token[1] == '(');
175 /* TODO: All the array versions leak memory. Fix them. */
176 switch (token[0]) {
177 case NACL_SRPC_ARG_TYPE_INVALID:
178 arg->tag = NACL_SRPC_ARG_TYPE_INVALID;
179 break;
180 case NACL_SRPC_ARG_TYPE_BOOL:
181 val = strtol(&token[2], 0, 0);
182 arg->tag = NACL_SRPC_ARG_TYPE_BOOL;
183 arg->u.bval = val;
184 break;
185 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
186 dim = strtol(&token[2], 0, 0);
187 arg->tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
188 arg->u.caval.carr = (char*) calloc(dim, sizeof(char));
189 arg->u.caval.count = dim;
190 comma = strstr(token, ",");
191 if (comma) {
192 const char* p;
193 for (p = comma+1, i = 0; *p != ')' && i < dim; ++p, ++i)
194 arg->u.caval.carr[i] = *p;
196 break;
197 case NACL_SRPC_ARG_TYPE_DOUBLE:
198 arg->tag = NACL_SRPC_ARG_TYPE_DOUBLE;
199 arg->u.dval = strtod(&token[2], 0);
200 break;
201 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
202 dim = strtol(&token[2], 0, 0);
203 arg->tag = NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY;
204 arg->u.daval.darr = (double*) calloc(dim, sizeof(double));
205 CHECK(arg->u.daval.darr);
206 arg->u.daval.count = dim;
207 comma = token;
208 for (i = 0; i < dim; ++i) {
209 comma = strstr(comma, ",");
210 if (!comma) break;
211 ++comma;
212 arg->u.daval.darr[i] = strtod(comma, 0);
214 break;
215 case NACL_SRPC_ARG_TYPE_HANDLE:
216 val = strtol(&token[2], 0, 0);
217 arg->tag = NACL_SRPC_ARG_TYPE_HANDLE;
218 arg->u.hval = (void *)val;
219 break;
220 case NACL_SRPC_ARG_TYPE_INT:
221 val = strtol(&token[2], 0, 0);
222 arg->tag = NACL_SRPC_ARG_TYPE_INT;
223 arg->u.ival = val;
224 break;
225 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
226 dim = strtol(&token[2], 0, 0);
227 arg->tag = NACL_SRPC_ARG_TYPE_INT_ARRAY;
228 /* LEAK */
229 arg->u.iaval.iarr = (int*) calloc(dim, sizeof(int));
230 CHECK(arg->u.iaval.iarr);
231 arg->u.iaval.count = dim;
232 comma = token;
233 for (i = 0; i < dim; ++i) {
234 comma = strstr(comma, ",");
235 if (!comma) break;
236 ++comma;
237 arg->u.iaval.iarr[i] = strtol(comma, 0, 0);
239 break;
240 case NACL_SRPC_ARG_TYPE_STRING:
241 arg->tag = NACL_SRPC_ARG_TYPE_STRING;
242 /* this is a conservative estimate */
243 arg->u.sval = malloc(strlen(token));
244 ScanEscapeString(arg->u.sval, token + 2);
245 break;
246 default:
247 return -1;
250 return 1;
253 int ParseArgs(NaClSrpcArg* arg, const TOKEN* token, int n) {
254 int i;
255 for (i = 0; i < n; ++i) {
256 if (ParseArg(&arg[i], token[i].start) < 0)
257 return -1;
259 return n;
262 void DumpArg(const NaClSrpcArg* arg) {
263 unsigned int count;
264 unsigned int i;
266 switch(arg->tag) {
267 case NACL_SRPC_ARG_TYPE_INVALID:
268 printf("X()");
269 break;
270 case NACL_SRPC_ARG_TYPE_BOOL:
271 printf("b(%d)", arg->u.bval);
272 break;
273 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
274 for (i = 0; i < arg->u.caval.count; ++i)
275 putchar(arg->u.caval.carr[i]);
276 break;
277 case NACL_SRPC_ARG_TYPE_DOUBLE:
278 printf("d(%f)", arg->u.dval);
279 break;
280 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
281 count = arg->u.daval.count;
282 printf("D(%d", count);
283 for (i=0; i < count; ++i)
284 printf(",%f", arg->u.daval.darr[i]);
285 printf(")");
286 break;
287 case NACL_SRPC_ARG_TYPE_HANDLE:
288 printf("h(%x)", (unsigned int) arg->u.hval);
289 break;
290 case NACL_SRPC_ARG_TYPE_INT:
291 printf("i(%d)", arg->u.ival);
292 break;
293 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
294 count = arg->u.iaval.count;
295 printf("I(%d", count);
296 for (i=0; i < count; ++i)
297 printf(",%d", arg->u.iaval.iarr[i]);
298 printf(")");
299 break;
300 case NACL_SRPC_ARG_TYPE_STRING:
301 /* TODO: do proper escaping */
302 printf("s(\"%s\")", arg->u.sval);
303 break;
304 default:
305 break;
309 void DumpArgs(const NaClSrpcArg* arg, int n) {
310 int i;
311 for (i=0; i<n; ++i) {
312 printf(" ");
313 DumpArg(&arg[i]);
315 printf("\n");
318 void BuildArgVec(NaClSrpcArg* argv[], NaClSrpcArg arg[], int count) {
319 int i;
320 CHECK(count < NACL_SRPC_MAX_ARGS);
321 for (i = 0; i < count; ++i) {
322 argv[i] = &arg[i];
324 argv[count] = NULL;
327 void FreeArrayArgs(NaClSrpcArg arg[], int count) {
328 int i;
329 for (i = 0; i < count; ++i) {
330 switch(arg[i].tag) {
331 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
332 free(arg[i].u.caval.carr);
333 break;
334 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
335 free(arg[i].u.daval.darr);
336 break;
337 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
338 free(arg[i].u.iaval.iarr);
339 break;
340 case NACL_SRPC_ARG_TYPE_INVALID:
341 case NACL_SRPC_ARG_TYPE_BOOL:
342 case NACL_SRPC_ARG_TYPE_DOUBLE:
343 case NACL_SRPC_ARG_TYPE_HANDLE:
344 case NACL_SRPC_ARG_TYPE_INT:
345 case NACL_SRPC_ARG_TYPE_STRING:
346 default:
347 break;
352 static void CommandLoop(NaClHandle imc_handle) {
353 NaClSrpcError errcode;
354 NaClSrpcChannel rpc_channel;
355 int command_count = 0;
357 NaClSrpcClientCtor(&rpc_channel, NaClSrpcImcDescTypeFromHandle(imc_handle));
360 * Process rpcs.
362 for (;;) {
363 char buffer[4096];
364 TOKEN tokens[NACL_SRPC_MAX_ARGS];
365 int n;
366 const char *command;
368 fprintf(stderr, "%d> ", command_count);
369 ++command_count;
371 if (!fgets(buffer, sizeof(buffer), stdin))
372 break;
374 n = Tokenize(buffer, tokens, NACL_SRPC_MAX_ARGS);
376 if (n < 1) {
377 if (n < 0)
378 fprintf(stderr, "bad line\n");
379 continue;
382 command = tokens[0].start;
383 if (0 == strcmp("#", command)) {
384 continue;
385 } else if (0 == strcmp("service", command)) {
386 NaClSrpcDumpInterfaceDesc(&rpc_channel);
387 } else if (0 == strcmp("quit", command)) {
388 break;
389 } else if (0 == strcmp("rpc", command)) {
390 int int_out_sep;
391 int n_in;
392 NaClSrpcArg in[NACL_SRPC_MAX_ARGS];
393 NaClSrpcArg* inv[NACL_SRPC_MAX_ARGS + 1];
394 int n_out;
395 NaClSrpcArg out[NACL_SRPC_MAX_ARGS];
396 NaClSrpcArg* outv[NACL_SRPC_MAX_ARGS + 1];
397 int rpc_num;
399 if (n < 2) {
400 fprintf(stderr, "bad rpc command\n");
401 continue;
404 for (int_out_sep = 2; int_out_sep < n; ++int_out_sep) {
405 if (0 == strcmp(tokens[int_out_sep].start, "*"))
406 break;
409 if (int_out_sep == n) {
410 fprintf(stderr, "no in out arg separator for rpc command\n");
411 continue;
415 * Build the input parameter values.
418 n_in = int_out_sep - 2;
419 DEBUG("parsing in args %d\n", n_in);
420 BuildArgVec(inv, in, n_in);
422 if (ParseArgs(in, &tokens[2], n_in) < 0) {
423 fprintf(stderr, "bad input args for rpc\n");
424 continue;
428 * Build the output (rpc return) values.
431 n_out = n - int_out_sep - 1;
432 DEBUG("parsing out args %d\n", n_out);
433 BuildArgVec(outv, out, n_out);
435 if (ParseArgs(out, &tokens[int_out_sep + 1], n_out) < 0) {
436 fprintf(stderr, "bad output args for rpc\n");
437 continue;
440 rpc_num = NaClSrpcGetRpcNum(&rpc_channel, tokens[1].start);
441 if (rpc_num < 0) {
442 fprintf(stderr, "unknown rpc\n");
443 continue;
446 fprintf(stderr,"using rpc %s no %d\n", tokens[1].start, rpc_num);
447 errcode = NaClSrpcInvokeV(&rpc_channel, rpc_num, inv, outv);
448 if (NACL_SRPC_RESULT_OK != errcode) {
449 fprintf(stderr, "rpc call failed %s\n", NaClSrpcErrorString(errcode));
450 continue;
454 * dump result vector
456 printf("%s RESULTS: ", tokens[1].start);
457 DumpArgs(outv[0], n_out);
460 * Free the storage allocated for array valued parameters and returns.
462 FreeArrayArgs(in, n_in);
463 FreeArrayArgs(out, n_out);
464 } else {
465 fprintf(stderr, "unknown command\n");
466 continue;
471 * Shut down the rpc streams.
473 NaClSrpcDtor(&rpc_channel);
478 * This function works with the rpc services in tests/srpc to test the
479 * interfaces.
481 static void TestRandomRpcs(NaClHandle imc_handle) {
482 NaClSrpcArg in;
483 NaClSrpcArg* inv[] = { &in, NULL };
484 NaClSrpcArg out;
485 NaClSrpcArg* outv[] = { &out, NULL };
486 NaClSrpcError errcode;
487 NaClSrpcChannel rpc_channel;
488 int argument_count;
489 int return_count;
490 int i;
493 * Set up the connection to the child process.
495 NaClSrpcClientCtor(&rpc_channel, NaClSrpcImcDescTypeFromHandle(imc_handle));
497 * TODO: set up timing on both ends of the IMC channel.
500 do {
501 if (timed_rpc_method < 1 || timed_rpc_method >= rpc_channel.rpc_count) {
502 fprintf(stderr, "method number must be between 1 and %d (inclusive)\n",
503 rpc_channel.rpc_count - 1);
504 break;
507 argument_count = strlen(rpc_channel.rpc_descr[timed_rpc_method].in_args);
508 return_count = strlen(rpc_channel.rpc_descr[timed_rpc_method].out_args);
510 if (argument_count != return_count) {
511 fprintf(stderr, "method argument and return count must match\n");
512 break;
515 if (1 < argument_count) {
516 fprintf(stderr, "method must take zero or one argument\n");
517 break;
520 if (argument_count == 0) {
521 inv[0] = NULL;
522 outv[0] = NULL;
523 } else {
524 enum NaClSrpcArgType type;
525 static char c_in[MAX_ARRAY_SIZE];
526 static char c_out[MAX_ARRAY_SIZE];
527 static double d_in[MAX_ARRAY_SIZE / sizeof(double)];
528 static double d_out[MAX_ARRAY_SIZE / sizeof(double)];
529 static int i_in[MAX_ARRAY_SIZE / sizeof(int)];
530 static int i_out[MAX_ARRAY_SIZE / sizeof(int)];
531 char* macbeth =
532 "She should have died hereafter;"
533 "There would have been a time for such a word."
534 "To-morrow, and to-morrow, and to-morrow,"
535 "Creeps in this petty pace from day to day"
536 "To the last syllable of recorded time,"
537 "And all our yesterdays have lighted fools"
538 "The way to dusty death. Out, out, brief candle!"
539 "Life's but a walking shadow, a poor player"
540 "That struts and frets his hour upon the stage"
541 "And then is heard no more: it is a tale"
542 "Told by an idiot, full of sound and fury,"
543 "Signifying nothing";
545 in.tag = rpc_channel.rpc_descr[timed_rpc_method].in_args[0];
546 out.tag = rpc_channel.rpc_descr[timed_rpc_method].out_args[0];
548 type = rpc_channel.rpc_descr[timed_rpc_method].in_args[0];
549 switch (type) {
550 case NACL_SRPC_ARG_TYPE_BOOL:
551 in.u.bval = 1;
552 break;
553 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
554 in.u.caval.count = timed_rpc_bytes;
555 in.u.caval.carr = c_in;
556 out.u.caval.count = in.u.iaval.count;
557 out.u.caval.carr = c_out;
558 break;
559 case NACL_SRPC_ARG_TYPE_DOUBLE:
560 in.u.dval = 3.1415926;
561 break;
562 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
563 in.u.daval.count = timed_rpc_bytes / sizeof(double);
564 in.u.daval.darr = d_in;
565 out.u.daval.count = in.u.iaval.count;
566 out.u.daval.darr = d_out;
567 break;
568 case NACL_SRPC_ARG_TYPE_INT:
569 in.u.ival = -1;
570 break;
571 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
572 in.u.iaval.count = timed_rpc_bytes / sizeof(int);
573 in.u.iaval.iarr = i_in;
574 out.u.iaval.count = in.u.iaval.count;
575 out.u.iaval.iarr = i_out;
576 break;
577 case NACL_SRPC_ARG_TYPE_STRING:
578 /* TODO: needs length variation */
579 in.u.sval = macbeth;
580 break;
581 case NACL_SRPC_ARG_TYPE_INVALID:
582 case NACL_SRPC_ARG_TYPE_HANDLE:
583 continue;
588 * Do the rpcs.
590 for (i = 0; i < timed_rpc_count; ++i) {
591 errcode = NaClSrpcInvokeV(&rpc_channel, timed_rpc_method, inv, outv);
592 if (NACL_SRPC_RESULT_OK != errcode) {
593 fprintf(stderr, "rpc call failed %s\n", NaClSrpcErrorString(errcode));
594 break;
598 if (i == timed_rpc_count) {
599 NaClSrpcArg* timer_inv[] = { NULL };
600 NaClSrpcArg tm[4];
601 NaClSrpcArg* timer_outv[] = { &tm[0], &tm[1], &tm[2], &tm[3], NULL };
602 double total_server_usec;
603 double dummy_receive;
604 double dummy_imc_read;
605 double dummy_imc_write;
607 NaClSrpcGetUsecTimes(&rpc_channel,
608 &total_server_usec,
609 &dummy_receive,
610 &dummy_imc_read,
611 &dummy_imc_write);
612 printf("server time observed by client: %.6f sec\n",
613 total_server_usec / 1000000.0);
614 tm[0].tag = NACL_SRPC_ARG_TYPE_DOUBLE;
615 tm[1].tag = NACL_SRPC_ARG_TYPE_DOUBLE;
616 tm[2].tag = NACL_SRPC_ARG_TYPE_DOUBLE;
617 tm[3].tag = NACL_SRPC_ARG_TYPE_DOUBLE;
618 errcode = NaClSrpcInvokeV(&rpc_channel,
619 NACL_SRPC_GET_TIMES_METHOD,
620 timer_inv,
621 timer_outv);
622 printf("server send time: %.6f sec\n", tm[0].u.dval / 1000000.0);
623 printf("server receive time: %.6f sec\n", tm[1].u.dval / 1000000.0);
624 printf("imc read time: %.6f sec\n", tm[2].u.dval / 1000000.0);
625 printf("imc write time: %.6f sec\n", tm[3].u.dval / 1000000.0);
626 printf("PASS\n");
628 } while (0);
631 * Shut down the rpc streams.
633 NaClSrpcDtor(&rpc_channel);
637 #if defined(HAVE_SDL)
638 #include <SDL.h>
639 #endif
641 int main(int argc, char *argv[]) {
642 NaClHandle imc_handle;
643 struct NaClSelLdrLauncher* launcher;
644 int opt;
645 static char* application_name;
646 char* nextp;
647 int i;
648 int sel_ldr_argc;
649 char** tmp_ldr_argv;
650 char** sel_ldr_argv;
651 int module_argc;
652 char** module_argv;
654 /* Descriptor transfer requires the following. */
655 NaClNrdAllModulesInit();
657 /* The -p option can change the sel_ldr binary used. */
658 g_sel_ldr_pathname = kSelLdrPathname;
660 /* We are only testing if this count is not zero. */
661 timed_rpc_count = 0;
663 /* command line parsing */
664 while ((opt = getopt(argc, argv, "f:p:r:v")) != -1) {
665 switch (opt) {
666 case 'f':
667 application_name = optarg;
668 break;
669 case 'p':
670 g_sel_ldr_pathname = optarg;
671 break;
672 case 'r':
673 timed_rpc_count = strtol(optarg, &nextp, 0);
674 if (':' == *nextp) {
675 timed_rpc_method = strtol(nextp + 1, &nextp, 0);
676 if (':' == *nextp) {
677 timed_rpc_bytes = strtol(nextp + 1, 0, 0);
680 printf("Testing: %d iterations, method %d, %d bytes\n",
681 timed_rpc_count,
682 timed_rpc_method,
683 timed_rpc_bytes);
684 break;
685 case 'v':
686 NaClLogIncrVerbosity();
687 break;
688 default:
689 fprintf(stderr,
690 "Usage: sel_universal [-f nacl_file]\n"
691 " [-p sel_ldr]\n"
692 " [-r count:method:bytes]\n");
693 return -1;
698 * Pass any extra arguments on to sel_ldr or the application.
700 tmp_ldr_argv = NULL;
701 sel_ldr_argc = 0;
702 module_argv = NULL;
703 module_argc = 0;
704 for (i = 0; i < argc; ++i) {
705 if (tmp_ldr_argv == NULL) {
706 // sel_universal arguments come first.
707 if (!strcmp("--", argv[i])) {
708 tmp_ldr_argv = &argv[i + 1];
710 } else if (module_argv == NULL) {
711 // sel_ldr arguments come next.
712 if (!strcmp("--", argv[i])) {
713 module_argv = &argv[i + 1];
714 } else {
715 ++sel_ldr_argc;
717 } else {
718 // application arguments come last.
719 ++module_argc;
724 * Append the -P 5 option to the command line to pass the channel to the
725 * SRPC interface.
727 sel_ldr_argv = (char**) malloc(module_argc * sizeof(*module_argv));
728 sel_ldr_argv[0] = "-P";
729 sel_ldr_argv[1] = "5";
730 for (i = 0; i < sel_ldr_argc; ++i) {
731 sel_ldr_argv[i + 2] = tmp_ldr_argv[i];
735 * Start sel_ldr with the given application and arguments.
737 launcher = NaClSelLdrStart(application_name,
739 sel_ldr_argc + 2,
740 (const char**) sel_ldr_argv,
741 module_argc,
742 (const char**) module_argv);
743 imc_handle = NaClSelLdrGetChannel(launcher);
745 if (timed_rpc_count == 0) {
746 CommandLoop(imc_handle);
747 } else {
748 TestRandomRpcs(imc_handle);
751 NaClSelLdrShutdown(launcher);
753 NaClNrdAllModulesFini();
754 return 0;
757 #if NACL_WINDOWS
758 /* TODO: create one utility function to get usec times. */
759 static int gettimeofday(struct timeval *tv, struct timezone *tz) {
760 unsigned __int64 timer = 0;
761 FILETIME filetime;
762 GetSystemTimeAsFileTime(&filetime);
763 timer |= filetime.dwHighDateTime;
764 timer <<= 32;
765 timer |= filetime.dwLowDateTime;
766 /* FILETIME has 100ns precision. Convert to usec. */
767 timer /= 10;
768 tv->tv_sec = (long) (timer / 1000000UL);
769 tv->tv_usec = (long) (timer % 1000000UL);
770 return 0;
772 #endif