watchdog.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <time.h>
4 #include <errno.h>
5 #include <kuroko/kuroko.h>
6 #include <kuroko/vm.h>
7 #include <kuroko/debug.h>
8 #include <kuroko/util.h>
9 
10 #include "common.h"
11 
12 #define DEFAULT_LIMIT 500000
13 
14 static int usage(char * argv[]) {
15  fprintf(stderr, "usage: %s [-s COUNT] [-q] FILE [args...]\n", argv[0]);
16  return 1;
17 }
18 
19 static int help(char * argv[]) {
20  usage(argv);
21  fprintf(stderr,
22  "Run scripts with an instruction counter and halt when a "
23  "limit is exceeded. The default limit is %d. A total count of "
24  "executed instructions is printed after completion.\n"
25  "\n"
26  "Options:\n"
27  " -s COUNT Set watchdog timeout to COUNT instructions.\n"
28  " Specify -1 to set disable limit.\n"
29  " -q Do not print total instruction count.\n"
30  "\n"
31  " --help Show this help text.\n"
32  "\n",
33  DEFAULT_LIMIT);
34  return 0;
35 }
36 
37 
38 static size_t instrCounter = 0; /* Total counter of executed instructions */
39 static size_t stopAt = DEFAULT_LIMIT;
40 static int quiet = 0;
41 
42 int krk_callgrind_debuggerHook(KrkCallFrame * frame) {
43  instrCounter++;
44  if (instrCounter < stopAt) return KRK_DEBUGGER_STEP;
45  if (instrCounter == stopAt) {
46  krk_runtimeError(vm.exceptions->baseException, "Watchdog counter expired.");
47  }
48  return KRK_DEBUGGER_CONTINUE;
49 }
50 
51 
52 int main(int argc, char *argv[]) {
53  int opt;
54  while ((opt = getopt(argc, argv, "+:s:q-:")) != -1) {
55  switch (opt) {
56  case 's':
57  stopAt = strtoul(optarg,NULL,10);
58  break;
59  case 'q':
60  quiet = 1;
61  break;
62  case '?':
63  if (optopt != '-') {
64  fprintf(stderr, "%s: unrocognized option '%c'\n", argv[0], optopt);
65  return 1;
66  }
67  optarg = argv[optind]+1;
68  /* fall through */
69  case '-':
70  if (!strcmp(optarg,"help")) {
71  return help(argv);
72  } else {
73  fprintf(stderr, "%s: unrecognized option: '--%s'\n", argv[0], optarg);
74  return 1;
75  }
76  }
77  }
78 
79  if (optind == argc) {
80  return usage(argv);
81  }
82 
83  findInterpreter(argv);
84  krk_initVM(KRK_THREAD_SINGLE_STEP);
85  krk_debug_registerCallback(krk_callgrind_debuggerHook);
86  addArgs(argc,argv);
87 
88  krk_startModule("__main__");
89  krk_runfile(argv[optind],argv[optind]);
90 
91  if (!quiet) {
92  fprintf(stderr, "%zu total instructions\n", instrCounter);
93  }
94 
95  krk_freeVM();
96  return 0;
97 }
98 
99 
Functions for debugging bytecode execution.
int krk_debug_registerCallback(KrkDebugCallback hook)
Register a debugger callback.
Definition: debug.c:643
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
Top-level header with configuration macros.
Represents a managed call state in a VM thread.
Definition: vm.h:44
void krk_freeVM(void)
Release resources from the VM.
Definition: vm.c:953
void krk_initVM(int flags)
Initialize the VM at program startup.
Definition: vm.c:868
Utilities for creating native bindings.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
KrkValue krk_runfile(const char *fileName, const char *fromFile)
Load and run a source file and return when execution completes.
Definition: vm.c:3236
KrkInstance * krk_startModule(const char *name)
Set up a new module object in the current thread.
Definition: vm.c:3209