12 #elif defined(__OpenBSD__)
16 #include "shotgun/config.h"
17 #include "shotgun/lib/shotgun.h"
18 #include "shotgun/lib/string.h"
19 #include "shotgun/lib/io.h"
20 #include "shotgun/lib/hash.h"
21 #include "shotgun/lib/lookuptable.h"
22 #include "shotgun/lib/machine.h"
23 #include "shotgun/lib/array.h"
24 #include "shotgun/lib/ar.h"
25 #include "shotgun/lib/symbol.h"
26 #include "shotgun/lib/config_hash.h"
27 #include "shotgun/lib/methctx.h"
28 #include "shotgun/lib/tuple.h"
29 #include "shotgun/lib/subtend.h"
30 #include "shotgun/lib/subtend/nmc.h"
31 #include "shotgun/lib/instruction_names.h"
33 static int _recursive_reporting
= 0;
35 /* use this to convert symbol into Ruby string
38 #define SYM2STR(st, sym) rbx_string_as_cstr(st, rbs_symbol_to_string(st, sym))
41 outputs limited number of lines of VM call stack
42 current active machine used unless explicitly given
44 void machine_print_callstack_limited(machine m
, int maxlev
) {
46 const char *modname
, *methname
, *filename
;
47 struct fast_context
*fc
;
48 if(!m
) m
= current_machine
;
49 context
= m
->c
->active_context
;
51 /* flush stack and instruction pointers */
55 FASTCTX(context
)->ip
= m
->c
->ip
;
57 while(RTEST(context
) && maxlev
--) {
59 methctx_reference(m
->s
, context
);
60 fc
= FASTCTX(context
);
62 if(fc
->method_module
&& RTEST(fc
->method_module
)) {
63 modname
= SYM2STR(m
->s
, module_get_name(fc
->method_module
));
68 if(fc
->type
== FASTCTX_BLOCK
) {
70 } else if(fc
->name
&& RTEST(fc
->name
)) {
71 if(SYMBOL_P(fc
->name
)) {
72 methname
= SYM2STR(m
->s
, fc
->name
);
74 methname
= "<unknown>";
80 if(fc
->method
&& RTEST(fc
->method
)) {
81 tmp
= cmethod_get_file(fc
->method
);
83 filename
= SYM2STR(m
->s
, tmp
);
85 filename
= "<unknown>";
88 filename
= "<unknown>";
91 /* execution logging */
92 fprintf(stderr
, "%10p %s#%s+%d in %s:%d\n",
93 (void*)context
, modname
, methname
,
96 cpu_ip2line(m
->s
, fc
->method
, fc
->ip
)
98 /* transfer control back to message sender */
103 /* prints the whole VM call stack */
104 void machine_print_callstack(machine m
) {
105 machine_print_callstack_limited(m
, -1);
108 /* prints of given VM stack trace */
109 void machine_print_stack(machine m
) {
110 unsigned int i
, start
, end
;
113 /* TODO: document these magic numbers */
114 start
= (i
< 5 ? 0 : i
- 5);
115 end
= (i
+ 5 > m
->c
->stack_size
) ? m
->c
->stack_size
: i
+ 5;
116 for(i
= start
; i
< end
; i
++) {
118 printf("%4d => ", i
);
122 printf("%s\n", rbs_inspect_verbose(m
->s
, m
->c
->stack_top
[i
]));
127 /* prints VM registers content */
128 void machine_print_registers(machine m
) {
131 printf("IP: %04d\nSP: %04d\n", m
->c
->ip
, m
->c
->sp
);
132 if(NIL_P(m
->c
->exception
)) {
133 printf("Exception: none\n");
135 printf("Exception: %s\n", rbs_inspect(m
->s
, m
->c
->exception
));
139 /* handles error reporting */
140 void _machine_error_reporter(int sig
, siginfo_t
*info
, void *ctx
) {
142 rni_context
*rni_ctx
;
145 /* See if the error happened during the running of a C function.
146 If so, we raise an exception about the error. */
147 /* Grab Subtend context first */
148 rni_ctx
= subtend_retrieve_context();
149 if(rni_ctx
->nmc
&& rni_ctx
->nmc
->system_set
) {
150 /* TODO: generate the C backtrace as a string array and pass it
151 via the nmc or global_context so that the exception can include
153 /* Set RNI faulting instruction and switch to system context */
154 rni_ctx
->fault_address
= info
->si_addr
;
155 rni_ctx
->nmc
->jump_val
= SEGFAULT_DETECTED
;
156 setcontext(&rni_ctx
->nmc
->system
);
159 /* This is really nice. We don't have to do this check at every
160 fetch, instead, let it segfault and handle it here.
161 The check for - 4 is because the bounds checks grabs the number
162 of fields from a ref right away, which is where it will segfault
163 if it's not a ref. The fields are 4 bytes into the header.
164 The check for - 8 is because it's common this happens when
165 trying to grab the class of a non-reference. The class is
166 8 bytes into the header. */
167 if(sig
== SIGSEGV
|| sig
== SIGBUS
) {
168 addr
= (OBJECT
)(info
->si_addr
);
169 if(!REFERENCE_P(addr
) || !REFERENCE_P(addr
- 4) || !REFERENCE_P(addr
- 8)) {
170 printf("Attempted to access field of non-reference.\n");
171 if(current_machine
->g_use_firesuit
) {
172 machine_handle_fire(FIRE_NULL
);
177 if(_recursive_reporting
) exit(-2);
178 _recursive_reporting
++;
182 signame
= "Segmentation fault (SIGSEGV)";
185 signame
= "Bus violation (SIGBUS)";
188 signame
= "Software abort (SIGABRT)";
191 signame
= "<UNKNOWN>";
194 printf("\nAn error has occured: %s (%d)\n\n", signame
, sig
);
196 if(getenv("CRASH_WAIT")) {
197 printf("Pausing so I can be debugged.\n");
199 printf("Continuing after debugger.\n");
202 printf("Ruby backtrace:\n");
203 machine_print_callstack(current_machine
);
205 printf("\nVM Registers:\n");
206 machine_print_registers(current_machine
);
211 /* initialize signals handling and errors reporting */
212 void machine_setup_signals(machine m
) {
213 m
->error_report
.sa_sigaction
= _machine_error_reporter
;
214 sigemptyset(&m
->error_report
.sa_mask
);
215 m
->error_report
.sa_flags
= SA_SIGINFO
;
216 sigaction(SIGSEGV
, &m
->error_report
, NULL
);
217 sigaction(SIGBUS
, &m
->error_report
, NULL
);
218 sigaction(SIGABRT
, &m
->error_report
, NULL
);
221 /* initialize event base used by libevent */
222 static void machine_setup_events(machine m
) {
223 /* libev will not "autodetect" kqueue because it is broken on darwin */
224 m
->s
->event_base
= ev_loop_new(EVFLAG_FORKCHECK
);
225 m
->s
->thread_infos
= NULL
;
228 /* Creates and initializes Rubinius VM.
229 * Sets up the VM CPU, machine message buckets,
230 * subtend, event handling, context and state,
231 * universe and everything.
234 machine
machine_new(environment e
) {
238 m
= calloc(1, sizeof(struct rubinius_machine
));
239 m
->g_use_firesuit
= 0;
240 m
->g_access_violation
= 0;
245 m
->message_read_fd
= pipes
[0];
246 m
->message_write_fd
= pipes
[1];
247 m
->s
= rubinius_state_new();
248 m
->c
= cpu_new(m
->s
);
249 cpu_run(m
->s
, m
->c
, TRUE
);
250 m
->c
->ip_ptr
= &m
->s
->external_ip
;
252 machine_setup_signals(m
);
253 machine_setup_events(m
);
255 cpu_initialize(m
->s
, m
->c
);
258 cpu_setup_top_scope(m
->s
, m
->c
);
259 cpu_initialize_context(m
->s
, m
->c
);
260 /* make MAIN Ruby contant point to main routine of the application*/
261 machine_set_const(m
, "MAIN", m
->c
->main
);
262 cpu_task_configure_preemption(m
->s
);
263 environment_add_machine(e
, m
);
265 m
->s
->om
->bootstrap_loaded
= 1;
270 void machine_destroy(machine m
) {
276 /* handles errors gracefully */
277 void machine_handle_fire(int kind
) {
278 /* store type of violation */
279 current_machine
->g_access_violation
= kind
;
280 /* then switch to special context to handle it gracefully */
281 setcontext(¤t_machine
->g_firesuit
);
284 /* handles type errors in the VM: error message and type are preserved */
285 void machine_handle_type_error(OBJECT obj
, const char *message
) {
286 current_machine
->g_firesuit_message
= strdup(message
);
289 current_machine
->g_firesuit_arg
= FixnumType
;
290 } else if(SYMBOL_P(obj
)) {
291 current_machine
->g_firesuit_arg
= SymbolType
;
292 } else if(REFERENCE_P(obj
)) {
293 current_machine
->g_firesuit_arg
= obj
->obj_type
;
294 } else if(NIL_P(obj
)) {
295 current_machine
->g_firesuit_arg
= NilType
;
297 current_machine
->g_firesuit_arg
= 0;
299 machine_handle_fire(FIRE_TYPE
);
302 /* handles failed assertions in the VM code */
303 void machine_handle_assert(const char *reason
, const char *file
, int line
) {
304 fprintf(stderr
, "VM Assertion: %s (%s:%d)\n", reason
, file
, line
);
306 printf("\nRuby backtrace:\n");
307 machine_print_callstack(current_machine
);
309 if(!current_machine
->g_use_firesuit
) abort();
310 current_machine
->g_access_violation
= FIRE_ASSERT
;
311 setcontext(¤t_machine
->g_firesuit
);
314 /* returns unmarshalled file */
315 OBJECT
machine_load_file(machine m
, const char *path
) {
316 return cpu_unmarshal_file(m
->s
, path
, 0);
319 void machine_show_exception(machine m
, OBJECT exc
) {
322 printf("\nError: An unhandled exception has terminated this VM.\n");
323 msg
= exception_get_message(exc
);
324 if(REFERENCE_P(msg
)) {
325 buf
= rbx_string_as_cstr(m
->s
, msg
);
327 buf
= "<no message>";
329 printf(" => %s (%s)\n\n", buf
, rbs_inspect(m
->s
, exc
->klass
));
331 /* Restore the context it happened at so print_callstack shows it. */
332 m
->c
->active_context
= exception_get_context(exc
);
333 machine_print_callstack(m
);
337 /* initializes VM globals, clears instruction pointer, op, firesuit and so forth.
338 returns FALSE on exception
340 int machine_run(machine m
) {
341 cpu_run(m
->s
, m
->c
, 0);
342 m
->c
->ip_ptr
= &m
->s
->external_ip
;
344 if(RTEST(m
->c
->exception
)) {
345 printf("Toplevel exception detected.\n");
346 machine_show_exception(m
, m
->c
->exception
);
352 /* loads and executes a script. Returns FALSE if load failed. */
353 int machine_run_file(machine m
, const char *path
) {
357 if(m
->s
->excessive_tracing
) {
358 printf("[ Loading file %s]\n", path
);
361 meth
= machine_load_file(m
, path
);
363 printf("Unable to load '%s'.\n", path
);
367 /* re-init cpu stack */
369 cpu_stack_push(m
->s
, m
->c
, meth
, FALSE
);
370 cpu_run_script(m
->s
, m
->c
, meth
);
371 out
= machine_run(m
);
372 if(m
->s
->excessive_tracing
) {
373 printf("[ Finished loading file %s]\n", path
);
378 /* sets contstand under given module or class */
379 void machine_set_const_under(machine m
, const char *str
, OBJECT val
, OBJECT under
) {
381 tbl
= module_get_constants(under
);
382 lookuptable_store(m
->s
, tbl
, string_new(m
->s
, str
), val
);
385 /* Sets constant under Object class */
386 void machine_set_const(machine m
, const char *str
, OBJECT val
) {
387 machine_set_const_under(m
, str
, val
, m
->s
->global
->object
);
390 /* stores Ruby VM launch arguments */
391 void machine_save_args(machine m
, int argc
, char **argv
) {
393 na
= calloc(argc
, sizeof(char*));
394 memcpy(na
, argv
, argc
);
398 machine_setup_ruby(m
, argv
[0]);
399 machine_setup_argv(m
, argc
, argv
);
402 /* Sets standard IO streams (stdin, stdout, stderr) to Ruby constants */
403 void machine_setup_standard_io(machine m
) {
404 machine_set_const(m
, "STDIN", io_new(m
->s
, 0, "r"));
405 machine_set_const(m
, "STDOUT", io_new(m
->s
, 1, "w"));
406 machine_set_const(m
, "STDERR", io_new(m
->s
, 2, "w"));
409 int *machine_setup_piped_io(machine m
) {
419 machine_set_const(m
, "STDIN", io_new(m
->s
, pin
[0], "r"));
420 machine_set_const(m
, "STDOUT", io_new(m
->s
, pout
[1], "w"));
421 machine_set_const(m
, "STDERR", io_new(m
->s
, perr
[1], "w"));
423 pipes
= ALLOC_N(int, 3);
431 /* sets up RUBY_BIN_PATH Ruby constant and VM interpreter name */
432 void machine_setup_ruby(machine m
, char *name
) {
433 char buf
[MAXPATHLEN
];
436 HACK: this should be replaced by normal ruby code.
440 getcwd(wd
, MAXPATHLEN
);
441 snprintf(buf
, MAXPATHLEN
, "%s/%s", wd
, name
);
444 machine_set_const(m
, "RUBY_BIN_PATH", string_new(m
->s
, name
));
445 m
->interpreter
= strdup(name
);
448 /* sets ARGV and ARG0 Ruby constants */
449 void machine_setup_argv(machine m
, int argc
, char **argv
) {
453 machine_set_const(m
, "ARG0", string_new(m
->s
, argv
[0]));
455 ary
= array_new(m
->s
, argc
- 1);
456 for(i
= 0; i
< argc
- 1; i
++) {
457 array_set(m
->s
, ary
, i
, string_new(m
->s
, argv
[i
+1]));
460 machine_set_const(m
, "ARGV", ary
);
463 /* utility: checks whether string contains only digits */
464 int is_number(char *str
) {
466 if(!isdigit(*str
)) return FALSE
;
473 /* utility: strips trailing non-alnum chars from string */
474 static char *trim_str(char *str
) {
476 while(*str
&& !isalnum(*str
) && *str
!= '/') str
++;
478 for(i
= strlen(str
) - 1; str
[i
] && !isalnum(str
[i
]) && *str
!= '/'; i
++) {
485 static void machine_parse_config_var(machine m
, const char *input
) {
486 char *name
, *val
, *var
, *eq
;
489 eq
= strchr(var
, '=');
494 name
= trim_str(var
);
497 if(!strcmp("include", name
)) {
498 machine_parse_config_file(m
, val
);
501 printf("[config] '%s' => '%s'\n", name
, val
);
504 ht_config_insert(m
->s
->config
, cstr2bstr(name
), cstr2bstr(val
));
508 printf("[config] '%s' => '1'\n", var
);
511 name
= trim_str(var
);
512 ht_config_insert(m
->s
->config
, cstr2bstr(name
), cstr2bstr("1"));
518 void machine_parse_configs(machine m
, const char *config
) {
522 semi
= strstr(config
, ";");
525 strncpy(tmp
, config
, sz
);
527 machine_parse_config_var(m
, tmp
);
529 semi
= strstr(config
, ";");
532 machine_parse_config_var(m
, config
);
535 void machine_parse_config_file(machine m
, const char *path
) {
539 fo
= fopen(path
, "r");
542 while (fgets(line
, sizeof(line
), fo
)) {
544 machine_parse_config_var(m
, line
);
551 void machine_migrate_config(machine m
) {
552 /* hash table iterator */
553 struct hashtable_itr iter
;
557 /* initialize new hash for environment global configuration */
558 m
->s
->global
->config
= hash_new_sized(m
->s
, 500);
560 if(hashtable_count(m
->s
->config
) > 0) {
561 hashtable_iterator_init(&iter
, m
->s
->config
);
566 bstring k
= (bstring
)hashtable_iterator_key(&iter
);
567 bstring v
= (bstring
)hashtable_iterator_value(&iter
);
568 /* object key: Ruby string created from bstring library C string */
569 ok
= string_newfrombstr(m
->s
, k
);
570 if(is_number(bdata(v
))) {
571 ov
= LL2N(strtoll(bdatae(v
,""), NULL
, 10));
573 ov
= string_newfrombstr(m
->s
, v
);
576 hash_set(m
->s
, m
->s
->global
->config
, ok
, ov
);
577 } while (hashtable_iterator_advance(&iter
));
580 /* Make Rubinius::RUBY_CONFIG point to global configuration */
581 rbx_module
= rbs_const_get(m
->s
, m
->s
->global
->object
, "Rubinius");
582 machine_set_const_under(m
, "RUBY_CONFIG", m
->s
->global
->config
, rbx_module
);
583 machine_setup_from_config(m
);
586 /* applies debug configuraiton options to VM state */
587 void machine_setup_from_config(machine m
) {
590 s
= cstr2bstr("rbx.debug.trace");
592 if(ht_config_search(m
->s
->config
, s
)) {
593 m
->s
->excessive_tracing
= 1;
596 bassigncstr (s
, "rbx.debug.gc");
598 if(ht_config_search(m
->s
->config
, s
)) {
605 /* initializes platform and arc related Ruby constants like RUBY_PLATFORM, OS and L64 */
606 void machine_setup_config(machine m
) {
612 mod
= rbs_const_get(m
->s
, m
->s
->global
->object
, "Rubinius");
613 machine_set_const(m
, "RUBY_PLATFORM", string_new(m
->s
, CONFIG_HOST
));
614 machine_set_const(m
, "RUBY_RELEASE_DATE", string_new(m
->s
, CONFIG_RELDATE
));
615 machine_set_const_under(m
, "RBX_VERSION", string_new(m
->s
, CONFIG_VERSION
), mod
);
616 machine_set_const_under(m
, "RUBY_VERSION", string_new(m
->s
, CONFIG_RUBY_VERSION
), mod
);
617 machine_set_const_under(m
, "RUBY_PATCHLEVEL", string_new(m
->s
, CONFIG_RUBY_PATCHLEVEL
), mod
);
618 machine_set_const_under(m
, "VERSION", string_new(m
->s
, CONFIG_RUBY_VERSION
), mod
);
619 machine_set_const_under(m
, "RUBY_ENGINE", string_new(m
->s
, CONFIG_ENGINE
), mod
);
620 machine_set_const_under(m
, "BUILDREV", string_new(m
->s
, CONFIG_BUILDREV
), mod
);
621 machine_set_const_under(m
, "CODE_PATH", string_new(m
->s
, CONFIG_CODEPATH
), mod
);
622 machine_set_const_under(m
, "EXT_PATH", string_new(m
->s
, CONFIG_EXTPATH
), mod
);
623 machine_set_const_under(m
, "RBA_PATH", string_new(m
->s
, CONFIG_RBAPATH
), mod
);
625 machine_set_const_under(m
, "WORDSIZE", I2N(CONFIG_WORDSIZE
), mod
);
627 #if defined(__ppc__) || defined(__POWERPC__) || defined(_POWER)
628 machine_set_const_under(m
, "PLATFORM", SYM("ppc"), mod
);
629 #elif defined(__amd64__)
630 machine_set_const_under(m
, "PLATFORM", SYM("amd64"), mod
);
631 #elif defined(i386) || defined(__i386__)
632 machine_set_const_under(m
, "PLATFORM", SYM("x86"), mod
);
633 #elif defined(__alpha) || defined(__alpha__)
634 machine_set_const_under(m
, "PLATFORM", SYM("alpha"), mod
);
635 #elif defined(VAX) || defined(__VAX)
636 machine_set_const_under(m
, "PLATFORM", SYM("vax"), mod
);
637 #elif defined(__hppa__)
638 machine_set_const_under(m
, "PLATFORM", SYM("hppa"), mod
);
639 #elif defined(__sparc__)
640 machine_set_const_under(m
, "PLATFORM", SYM("sparc"), mod
);
641 #elif defined(__s390__)
642 machine_set_const_under(m
, "PLATFORM", SYM("s390"), mod
);
643 #elif (defined(TARGET_CPU_68K) || defined(__CFM68K__) || defined(m68k) || defined(_M_M68K))
644 machine_set_const_under(m
, "PLATFORM", SYM("m68k"), mod
);
646 machine_set_const_under(m
, "PLATFORM", SYM("unknown"), mod
);
649 #if defined(__APPLE__) || defined(__MACH__)
650 machine_set_const_under(m
, "OS", SYM("darwin"), mod
);
651 #elif defined(__linux__) || defined(linux) || defined(__linux)
652 machine_set_const_under(m
, "OS", SYM("linux"), mod
);
653 #elif defined(__FreeBSD__)
654 machine_set_const_under(m
, "OS", SYM("freebsd"), mod
);
655 #elif defined(__CYGWIN__)
656 machine_set_const_under(m
, "OS", SYM("cygwin"), mod
);
657 #elif defined(__OS2__)
658 machine_set_const_under(m
, "OS", SYM("os2"), mod
);
659 #elif defined(__NT__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
660 machine_set_const_under(m
, "OS", SYM("win32"), mod
);
661 #elif defined(__WINDOWS__)
662 machine_set_const_under(m
, "OS", SYM("windows_3x"), mod
);
663 #elif defined(__NETWARE_386__)
664 machine_set_const_under(m
, "OS", SYM("netware"), mod
);
665 #elif defined(__MSDOS__)
666 machine_set_const_under(m
, "OS", SYM("dos"), mod
);
667 #elif defined(VMS) || defined(__VMS__)
668 machine_set_const_under(m
, "OS", SYM("vms"), mod
);
669 #elif defined(__hpux__)
670 machine_set_const_under(m
, "OS", SYM("hpux"), mod
);
671 #elif defined(__sun__) || defined(__sun)
672 machine_set_const_under(m
, "OS", SYM("solaris"), mod
);
673 #elif defined(__svr4__)
674 machine_set_const_under(m
, "OS", SYM("unixware"), mod
);
676 machine_set_const_under(m
, "OS", SYM("aix"), mod
);
677 #elif (defined(_SCO_DS) && defined(_SCO_ELF) && defined(_SCO_XPG_VERS) && defined(_SCO_C_DIALECT))
678 machine_set_const_under(m
, "OS", SYM("openserver"), mod
);
679 #elif defined(__unix__)
680 machine_set_const_under(m
, "OS", SYM("decunix"), mod
);
682 machine_set_const_under(m
, "OS", SYM("unknown"), mod
);
685 #if defined(__VERSION__)
686 machine_set_const_under(m
, "COMPILER_VERSION", string_new(m
->s
, __VERSION__
), mod
);
688 machine_set_const_under(m
, "COMPILER_VERSION", Qnil
, mod
);
691 #if defined(_MSC_VER)
692 machine_set_const_under(m
, "COMPILER", SYM("microsoft"), mod
);
693 #elif defined(__DECC) || defined(VAXC)
694 machine_set_const_under(m
, "COMPILER", SYM("digital"), mod
);
695 #elif defined(__BORLANDC__)
696 machine_set_const_under(m
, "COMPILER", SYM("borland"), mod
);
697 #elif defined(__WATCOMC__)
698 machine_set_const_under(m
, "COMPILER", SYM("watcom"), mod
);
699 #elif defined(__GNUC__)
700 machine_set_const_under(m
, "COMPILER", SYM("gcc"), mod
);
701 #elif defined(__MWERKS__)
702 machine_set_const_under(m
, "COMPILER", SYM("metrowerks"), mod
);
703 #elif defined(__IBMC__) || defined(__IBMCPP__)
704 machine_set_const_under(m
, "COMPILER", SYM("ibm"), mod
);
705 #elif defined(__SUNPRO_C)
706 machine_set_const_under(m
, "COMPILER", SYM("sunpro"), mod
);
708 machine_set_const_under(m
, "COMPILER", SYM("unknown"), mod
);
711 #if CONFIG_BIG_ENDIAN
712 machine_set_const_under(m
, "ENDIAN", SYM("big"), mod
);
714 machine_set_const_under(m
, "ENDIAN", SYM("little"), mod
);
717 if(sizeof(long) == 8) {
718 machine_set_const_under(m
, "L64", Qtrue
, mod
);
720 machine_set_const_under(m
, "L64", Qfalse
, mod
);
723 /* Shared library file extension */
724 #if defined(_WIN32) || defined(__NT__) || defined(WIN32) || defined(__WIN32__)
725 #define LIBSUFFIX "dll"
726 #elif defined(__APPLE__)
727 #define LIBSUFFIX "bundle"
728 #define ALT_LIBSUFFIX "dylib"
730 #define LIBSUFFIX "so"
733 machine_set_const_under(m
, "LIBSUFFIX", string_new(m
->s
, LIBSUFFIX
), mod
);
735 machine_set_const_under(m
, "ALT_LIBSUFFIX", string_new(m
->s
, ALT_LIBSUFFIX
), mod
);
738 machine_set_const_under(m
, "COMPILER_PATH", string_new(m
->s
, CONFIG_CC
), mod
);
741 machine_set_const_under(m
, "Terminal", string_new(m
->s
, ttyname(0)), mod
);
743 machine_set_const_under(m
, "Terminal", Qfalse
, mod
);
746 machine_set_const_under(m
, "DEBUG_INST", I2N(CPU_INSTRUCTION_YIELD_DEBUGGER
), mod
);
748 machine_set_const_under(m
, "VM_ID", I2N(m
->id
), mod
);
749 machine_set_const_under(m
, "VM_INFERIOR", m
->sub
? Qtrue
: Qfalse
, mod
);
751 /* This feels like the wrong place for this, but it works. */
752 machine_set_const_under(m
, "MESSAGE_IO", io_new(m
->s
, m
->message_read_fd
, "r"), mod
);
755 /* sets up debugging flags */
756 void machine_config_env(machine m
) {
758 if(getenv("RDEBUG")) {
762 if(getenv("RBX_CONFIG")) {
766 config
= getenv("RBX");
768 machine_parse_configs(m
, config
);
771 config
= getenv("RBX_CONFFILE");
773 machine_parse_config_file(m
, config
);
777 /* loads files in the directory, respects load order hint file .load_order.txt */
778 int machine_load_directory(machine m
, const char *prefix
) {
782 size_t buf_siz
= 1024, prefix_len
;
784 prefix_len
= strlen(prefix
);
785 if(prefix_len
> (buf_siz
- 16)) return FALSE
;
787 path
= ALLOC_N(char, buf_siz
);
788 memcpy(path
, prefix
, prefix_len
);
789 strcpy(path
+ prefix_len
, "/.load_order.txt");
791 fp
= fopen(path
, "r");
793 printf("Unable to open directory '%s'\n", prefix
);
798 file
= &path
[prefix_len
+ 1];
800 while (fgets(file
, buf_siz
- prefix_len
, fp
)) {
803 /* Get rid of the \n on the end. */
804 file_len
= strlen(file
);
806 if (path
[prefix_len
+ file_len
] == '\n')
807 path
[prefix_len
+ file_len
] = 0;
809 if(!machine_run_file(m
, path
)) {
822 int machine_load_object(machine m
, char *name
, uint8_t *data
, long length
) {
825 if(m
->s
->excessive_tracing
) {
826 printf("[ Loading archived file %s]\n", name
);
829 cm
= cpu_unmarshal(m
->s
, data
, length
, 0);
835 /* We push this on the stack so it's properly seen by the GCs */
836 cpu_stack_push(m
->s
, m
->c
, cm
, FALSE
);
837 cpu_run_script(m
->s
, m
->c
, cm
);
839 if(!machine_run(m
)) {
840 printf("Unable to run '%s'\n", name
);
844 /* Pop the return value and script object. */
845 (void)cpu_stack_pop(m
->s
, m
->c
);
846 (void)cpu_stack_pop(m
->s
, m
->c
);
852 * loads and executes Rubinius bytecode archive (*.rba, similar to *.jar or *.elc)
854 * Rubinius' rba files are essentialy zip archived bytecode. .load_order file
855 * must be loaded first to respect bytecode dependencies.
857 int machine_load_ar(machine m
, const char *path
) {
860 if(m
->s
->excessive_tracing
) {
861 printf("[ Loading ar rba %s]\n", path
);
864 ret
= ar_each_file(m
, path
, machine_load_object
);
866 if(m
->s
->excessive_tracing
) {
867 printf("[ Finished loading ar rba %s]\n", path
);
873 int machine_load_rba(machine m
, const char *path
) {
874 return machine_load_ar(m
, path
);
877 int machine_load_bundle(machine m
, const char *path
) {
880 /* return false if file does no exist */
881 if(stat(path
, &sb
) != 0) return FALSE
;
883 if(S_ISDIR(sb
.st_mode
)) {
884 return machine_load_directory(m
, path
);
887 return machine_load_rba(m
, path
);
890 /* 1. saves the command line arguments used to invoke the VM.
891 * 2. initializes platform and arc related Ruby constants
892 * 3. sets up debugging flags from configuration
893 * 4. sets standard IO streams (stdin, stdout, stderr) to Ruby constants STDIN, STDOUT and STDERR
895 void machine_setup_normal(machine m
, int argc
, char **argv
) {
896 machine_save_args(m
, argc
, argv
);
897 machine_setup_config(m
);
898 machine_config_env(m
);
899 machine_setup_standard_io(m
);
903 * 1. sets inferior machine flag to true (inferior machine is one spawned by another, a "child")
904 * 2. saves the command line arguments used to invoke the VM.
905 * 3. initializes platform and arc related Ruby constants
906 * 4. sets up debugging flags from configuration
907 * 5. sets up piped IO streams (stdin, stdout, stderr) to Ruby constants STDIN, STDOUT and STDERR
909 int *machine_setup_thread(machine m
, int argc
, char **argv
) {
911 machine_save_args(m
, argc
, argv
);
912 machine_setup_config(m
);
913 machine_config_env(m
);
914 return machine_setup_piped_io(m
);