*** empty log message ***
[chuck-blob.git] / v2 / chuck_main.cpp
blob2123a0a802e869defbc9e02c9cc14a498cb56a0f
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_main.cpp
27 // desc: chuck entry point
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // additional contributors:
32 // Ananya Misra (amisra@cs.princeton.edu)
33 // Spencer Salazar (salazar@cs.princeton.edu)
34 // date: version 1.1.x.x - Autumn 2002
35 // version 1.2.x.x - Autumn 2004
36 //-----------------------------------------------------------------------------
37 #include <stdio.h>
38 #include <string.h>
39 #include <time.h>
41 #include "chuck_compile.h"
42 #include "chuck_vm.h"
43 #include "chuck_bbq.h"
44 #include "chuck_errmsg.h"
45 #include "chuck_lang.h"
46 #include "chuck_otf.h"
47 #include "chuck_shell.h"
48 #include "chuck_console.h"
49 #include "chuck_globals.h"
51 #include "util_math.h"
52 #include "util_string.h"
53 #include "util_thread.h"
54 #include "util_network.h"
55 #include "hidio_sdl.h"
57 #include <signal.h>
58 #ifndef __PLATFORM_WIN32__
59 #include <unistd.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #endif
65 // global variables
66 #if defined(__MACOSX_CORE__)
67 t_CKINT g_priority = 80;
68 t_CKINT g_priority_low = 60;
69 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
70 t_CKINT g_priority = THREAD_PRIORITY_HIGHEST;
71 t_CKINT g_priority_low = THREAD_PRIORITY_HIGHEST;
72 #else
73 t_CKINT g_priority = 0x7fffffff;
74 t_CKINT g_priority_low = 0x7fffffff;
75 #endif
77 // thread id for otf thread
78 CHUCK_THREAD g_tid_otf = 0;
79 // thread id for shell
80 CHUCK_THREAD g_tid_shell = 0;
82 // default destination host name
83 char g_host[256] = "127.0.0.1";
88 //-----------------------------------------------------------------------------
89 // name: signal_int()
90 // desc: ...
91 //-----------------------------------------------------------------------------
92 extern "C" void signal_int( int sig_num )
94 fprintf( stderr, "[chuck]: cleaning up...\n" );
96 if( g_vm )
98 // get vm
99 Chuck_VM * vm = g_vm;
100 Chuck_Compiler * compiler = g_compiler;
101 // flag the global one
102 g_vm = NULL;
103 g_compiler = NULL;
104 // if not NULL
105 if( vm )
107 // stop
108 vm->stop();
109 // detach
110 all_detach();
113 // things don't work so good on windows...
114 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
115 // pthread_kill( g_tid_otf, 2 );
116 if( g_tid_otf ) pthread_cancel( g_tid_otf );
117 if( g_tid_whatever ) pthread_cancel( g_tid_whatever );
118 // if( g_tid_otf ) usleep( 50000 );
119 #else
120 // close handle
121 if( g_tid_otf ) CloseHandle( g_tid_otf );
122 #endif
123 // will this work for windows?
124 SAFE_DELETE( vm );
125 SAFE_DELETE( compiler );
127 // ck_close( g_sock );
130 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
131 // pthread_join( g_tid_otf, NULL );
132 #endif
134 exit(2);
140 //-----------------------------------------------------------------------------
141 // name: uh()
142 // desc: ...
143 //-----------------------------------------------------------------------------
144 static void uh( )
146 // TODO: play white noise and/or sound effects
147 srand( time( NULL ) );
148 while( true )
150 int n = (int)(rand() / (float)RAND_MAX * poop_size);
151 printf( "%s\n", poop[n] );
152 usleep( (unsigned long)(rand() / (float)RAND_MAX * 2000000) );
159 //-----------------------------------------------------------------------------
160 // name: init_shell()
161 // desc: ...
162 //-----------------------------------------------------------------------------
163 static t_CKBOOL init_shell( Chuck_Shell * shell, Chuck_Shell_UI * ui, Chuck_VM * vm )
165 // initialize shell UI
166 if( !ui->init() )
168 fprintf( stderr, "[chuck]: error starting shell UI...\n" );
169 return FALSE;
172 // initialize
173 if( !shell->init( vm, ui ) )
175 fprintf( stderr, "[chuck]: error starting shell...\n" );
176 return FALSE;
179 return TRUE;
185 //-----------------------------------------------------------------------------
186 // name: get_count()
187 // desc: ...
188 //-----------------------------------------------------------------------------
189 static t_CKBOOL get_count( const char * arg, t_CKUINT * out )
191 // no comment
192 if( !strncmp( arg, "--", 2 ) ) arg += 2;
193 else if( !strncmp( arg, "-", 1 ) ) arg += 1;
194 else return FALSE;
196 // end of string
197 if( *arg == '\0' ) return FALSE;
198 // not digit
199 if( *arg < '0' || *arg > '9' ) return FALSE;
201 // number
202 *out = (t_CKUINT)atoi( arg );
204 return TRUE;
210 //-----------------------------------------------------------------------------
211 // name: version()
212 // desc: ...
213 //-----------------------------------------------------------------------------
214 static void version()
216 fprintf( stderr, "\n" );
217 fprintf( stderr, "chuck version: %s\n", CK_VERSION );
218 #if defined(__PLATFORM_WIN32__)
219 fprintf( stderr, " exe target: microsoft win32\n" );
220 #elif defined(__WINDOWS_DS__)
221 fprintf( stderr, " exe target: microsoft win32 + cygwin\n" );
222 #elif defined(__LINUX_ALSA__)
223 fprintf( stderr, " exe target: linux (alsa)\n" );
224 #elif defined(__LINUX_OSS__)
225 fprintf( stderr, " exe target: linux (oss)\n" );
226 #elif defined(__LINUX_JACK__)
227 fprintf( stderr, " exe target: linux (jack)\n" );
228 #elif defined(__MACOSX_UB__)
229 fprintf( stderr, " exe target: mac os x : universal binary\n" );
230 #elif defined(__MACOSX_CORE__) && defined(__LITTLE_ENDIAN__)
231 fprintf( stderr, " exe target: mac os x : intel\n" );
232 #elif defined(__MACOSX_CORE__)
233 fprintf( stderr, " exe target: mac os x : powerpc\n" );
234 #else
235 fprintf( stderr, " exe target: uh... unknown\n" );
236 #endif
237 fprintf( stderr, " http://chuck.cs.princeton.edu/\n\n" );
243 //-----------------------------------------------------------------------------
244 // name: usage()
245 // desc: ...
246 //-----------------------------------------------------------------------------
247 static void usage()
249 fprintf( stderr, "usage: chuck --[options|commands] [+-=^] file1 file2 file3 ...\n" );
250 fprintf( stderr, " [options] = halt|loop|audio|silent|dump|nodump|server|about|\n" );
251 fprintf( stderr, " srate<N>|bufsize<N>|bufnum<N>|dac<N>|adc<N>|\n" );
252 fprintf( stderr, " remote<hostname>|port<N>|verbose<N>|probe|\n" );
253 fprintf( stderr, " channels<N>|out<N>|in<N>|shell|empty|level<N>|\n" );
254 fprintf( stderr, " blocking|callback|deprecate:{stop|warn|ignore}\n" );
255 fprintf( stderr, " [commands] = add|remove|replace|remove.all|status|time|kill\n" );
256 fprintf( stderr, " [+-=^] = shortcuts for add, remove, replace, status\n" );
257 version();
263 //-----------------------------------------------------------------------------
264 // name: main()
265 // desc: entry point
266 //-----------------------------------------------------------------------------
267 int main( int argc, const char ** argv )
269 Chuck_Compiler * compiler = NULL;
270 Chuck_VM * vm = NULL;
271 Chuck_VM_Code * code = NULL;
272 Chuck_VM_Shred * shred = NULL;
274 t_CKBOOL enable_audio = TRUE;
275 t_CKBOOL vm_halt = TRUE;
276 t_CKUINT srate = SAMPLING_RATE_DEFAULT;
277 t_CKUINT buffer_size = BUFFER_SIZE_DEFAULT;
278 t_CKUINT num_buffers = NUM_BUFFERS_DEFAULT;
279 t_CKUINT dac = 0;
280 t_CKUINT adc = 0;
281 t_CKUINT dac_chans = 2;
282 t_CKUINT adc_chans = 2;
283 t_CKBOOL dump = FALSE;
284 t_CKBOOL probe = FALSE;
285 t_CKBOOL set_priority = FALSE;
286 t_CKBOOL auto_depend = FALSE;
287 t_CKBOOL block = FALSE;
288 t_CKBOOL enable_shell = FALSE;
289 t_CKBOOL no_vm = FALSE;
290 t_CKBOOL load_hid = FALSE;
291 t_CKBOOL enable_server = TRUE;
292 t_CKBOOL do_watchdog = TRUE;
293 t_CKINT log_level = CK_LOG_CORE;
294 t_CKINT deprecate_level = 1; // warn
296 string filename = "";
297 vector<string> args;
299 #if defined(__MACOSX_CORE__)
300 do_watchdog = TRUE;
301 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
302 do_watchdog = TRUE;
303 #else
304 do_watchdog = FALSE;
305 #endif
307 t_CKUINT files = 0;
308 t_CKUINT count = 1;
309 t_CKINT i;
311 // set log level
312 EM_setlog( log_level );
314 // parse command line args
315 for( i = 1; i < argc; i++ )
317 if( argv[i][0] == '-' || argv[i][0] == '+' ||
318 argv[i][0] == '=' || argv[i][0] == '^' || argv[i][0] == '@' )
320 if( !strcmp(argv[i], "--dump") || !strcmp(argv[i], "+d")
321 || !strcmp(argv[i], "--nodump") || !strcmp(argv[i], "-d") )
322 continue;
323 else if( get_count( argv[i], &count ) )
324 continue;
325 else if( !strcmp(argv[i], "--audio") || !strcmp(argv[i], "-a") )
326 enable_audio = TRUE;
327 else if( !strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s") )
328 enable_audio = FALSE;
329 else if( !strcmp(argv[i], "--halt") || !strcmp(argv[i], "-t") )
330 vm_halt = TRUE;
331 else if( !strcmp(argv[i], "--loop") || !strcmp(argv[i], "-l") )
332 { vm_halt = FALSE; enable_server = TRUE; }
333 else if( !strcmp(argv[i], "--server") )
334 enable_server = TRUE;
335 else if( !strcmp(argv[i], "--standalone") )
336 enable_server = FALSE;
337 else if( !strcmp(argv[i], "--callback") )
338 block = FALSE;
339 else if( !strcmp(argv[i], "--blocking") )
340 block = TRUE;
341 else if( !strcmp(argv[i], "--hid") )
342 load_hid = TRUE;
343 else if( !strcmp(argv[i], "--shell") || !strcmp( argv[i], "-e" ) )
344 { enable_shell = TRUE; vm_halt = FALSE; }
345 else if( !strcmp(argv[i], "--empty") )
346 no_vm = TRUE;
347 else if( !strncmp(argv[i], "--srate", 7) )
348 srate = atoi( argv[i]+7 ) > 0 ? atoi( argv[i]+7 ) : srate;
349 else if( !strncmp(argv[i], "-r", 2) )
350 srate = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : srate;
351 else if( !strncmp(argv[i], "--bufsize", 9) )
352 buffer_size = atoi( argv[i]+9 ) > 0 ? atoi( argv[i]+9 ) : buffer_size;
353 else if( !strncmp(argv[i], "-b", 2) )
354 buffer_size = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : buffer_size;
355 else if( !strncmp(argv[i], "--bufnum", 8) )
356 num_buffers = atoi( argv[i]+8 ) > 0 ? atoi( argv[i]+8 ) : num_buffers;
357 else if( !strncmp(argv[i], "-n", 2) )
358 num_buffers = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : num_buffers;
359 else if( !strncmp(argv[i], "--dac", 5) )
360 dac = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 0;
361 else if( !strncmp(argv[i], "--adc", 5) )
362 adc = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 0;
363 else if( !strncmp(argv[i], "--channels", 10) )
364 dac_chans = adc_chans = atoi( argv[i]+10 ) > 0 ? atoi( argv[i]+10 ) : 2;
365 else if( !strncmp(argv[i], "-c", 2) )
366 dac_chans = adc_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
367 else if( !strncmp(argv[i], "--out", 5) )
368 dac_chans = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 2;
369 else if( !strncmp(argv[i], "-o", 2) )
370 dac_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
371 else if( !strncmp(argv[i], "--in", 4) )
372 adc_chans = atoi( argv[i]+4 ) > 0 ? atoi( argv[i]+4 ) : 2;
373 else if( !strncmp(argv[i], "-i", 2) )
374 adc_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
375 else if( !strncmp(argv[i], "--level", 7) )
376 { g_priority = atoi( argv[i]+7 ); set_priority = TRUE; }
377 else if( !strncmp(argv[i], "--watchdog", 10) )
378 { g_watchdog_timeout = atof( argv[i]+10 );
379 if( g_watchdog_timeout <= 0 ) g_watchdog_timeout = 0.5;
380 do_watchdog = TRUE; }
381 else if( !strncmp(argv[i], "--nowatchdog", 12) )
382 do_watchdog = FALSE;
383 else if( !strncmp(argv[i], "--remote", 8) )
384 strcpy( g_host, argv[i]+8 );
385 else if( !strncmp(argv[i], "@", 1) )
386 strcpy( g_host, argv[i]+1 );
387 else if( !strncmp(argv[i], "--port", 6) )
388 g_port = atoi( argv[i]+6 );
389 else if( !strncmp(argv[i], "-p", 2) )
390 g_port = atoi( argv[i]+2 );
391 else if( !strncmp(argv[i], "--auto", 6) )
392 auto_depend = TRUE;
393 else if( !strncmp(argv[i], "-u", 2) )
394 auto_depend = TRUE;
395 else if( !strncmp(argv[i], "--log", 5) )
396 log_level = argv[i][5] ? atoi( argv[i]+5 ) : CK_LOG_INFO;
397 else if( !strncmp(argv[i], "--verbose", 9) )
398 log_level = argv[i][9] ? atoi( argv[i]+9 ) : CK_LOG_INFO;
399 else if( !strncmp(argv[i], "-v", 2) )
400 log_level = argv[i][2] ? atoi( argv[i]+2 ) : CK_LOG_INFO;
401 else if( !strncmp(argv[i], "--deprecate", 11) )
403 // get the rest
404 string arg = argv[i]+11;
405 if( arg == ":stop" ) deprecate_level = 0;
406 else if( arg == ":warn" ) deprecate_level = 1;
407 else if( arg == ":ignore" ) deprecate_level = 2;
408 else
410 // error
411 fprintf( stderr, "[chuck]: invalid arguments for '--deprecate'...\n" );
412 fprintf( stderr, "[chuck]: ... (looking for :stop, :warn, or :ignore)\n" );
413 exit( 1 );
416 else if( !strcmp( argv[i], "--probe" ) )
417 probe = TRUE;
418 else if( !strcmp( argv[i], "--poop" ) )
419 uh();
420 else if( !strcmp( argv[i], "--caution-to-the-wind" ) )
421 g_enable_system_cmd = TRUE;
422 else if( !strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")
423 || !strcmp(argv[i], "--about") )
425 usage();
426 exit( 2 );
428 else if( !strcmp( argv[i], "--version" ) )
430 version();
431 exit( 2 );
433 else
435 // boost log level
436 g_otf_log = CK_LOG_CORE;
437 // flag
438 int is_otf = FALSE;
439 // log level
440 EM_setlog( log_level );
441 // do it
442 if( otf_send_cmd( argc, argv, i, g_host, g_port, &is_otf ) )
443 exit( 0 );
445 // is otf
446 if( is_otf ) exit( 1 );
448 // done
449 fprintf( stderr, "[chuck]: invalid flag '%s'\n", argv[i] );
450 usage();
451 exit( 1 );
454 else
455 files++;
458 // log level
459 EM_setlog( log_level );
461 // probe
462 if( probe )
464 Digitalio::probe();
466 EM_error2b( 0, "" );
467 probeMidiIn();
468 EM_error2b( 0, "" );
469 probeMidiOut();
470 EM_error2b( 0, "" );
472 //HidInManager::probeHidIn();
474 // exit
475 exit( 0 );
478 // check buffer size
479 buffer_size = ensurepow2( buffer_size );
480 // check mode and blocking
481 if( !enable_audio && !block ) block = TRUE;
482 // audio, boost
483 if( !set_priority && !block ) g_priority = g_priority_low;
484 if( !set_priority && !enable_audio ) g_priority = 0x7fffffff;
485 // set priority
486 Chuck_VM::our_priority = g_priority;
487 // set watchdog
488 g_do_watchdog = do_watchdog;
490 if ( !files && vm_halt && !enable_shell )
492 fprintf( stderr, "[chuck]: no input files... (try --help)\n" );
493 exit( 1 );
496 // shell initialization without vm
497 if( enable_shell && no_vm )
499 // instantiate
500 g_shell = new Chuck_Shell;
501 // initialize
502 if( !init_shell( g_shell, new Chuck_Console, NULL ) )
503 exit( 1 );
504 // no vm is needed, just start running the shell now
505 g_shell->run();
506 // clean up
507 SAFE_DELETE( g_shell );
508 // done
509 exit( 0 );
512 // make sure vm
513 if( no_vm )
515 fprintf( stderr, "[chuck]: '--empty' can only be used with shell...\n" );
516 exit( 1 );
519 // allocate the vm - needs the type system
520 vm = g_vm = new Chuck_VM;
521 if( !vm->initialize( enable_audio, vm_halt, srate, buffer_size,
522 num_buffers, dac, adc, dac_chans, adc_chans, block ) )
524 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
525 exit( 1 );
528 // allocate the compiler
529 compiler = g_compiler = new Chuck_Compiler;
530 // initialize the compiler
531 if( !compiler->initialize( vm ) )
533 fprintf( stderr, "[chuck]: error initializing compiler...\n" );
534 exit( 1 );
536 // enable dump
537 compiler->emitter->dump = dump;
538 // set auto depend
539 compiler->set_auto_depend( auto_depend );
541 // vm synthesis subsystem - needs the type system
542 if( !vm->initialize_synthesis( ) )
544 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
545 exit( 1 );
548 // pre-load hid
549 if( load_hid ) HidInManager::init();
551 // catch SIGINT
552 signal( SIGINT, signal_int );
553 #ifndef __PLATFORM_WIN32__
554 // catch SIGPIPE
555 signal( SIGPIPE, signal_pipe );
556 #endif
558 // shell initialization
559 if( enable_shell )
561 // instantiate
562 g_shell = new Chuck_Shell;
563 // initialize
564 if( !init_shell( g_shell, new Chuck_Console, vm ) )
565 exit( 1 );
568 // set deprecate
569 compiler->env->deprecate_level = deprecate_level;
571 // reset count
572 count = 1;
574 // log
575 EM_log( CK_LOG_SEVERE, "starting compilation..." );
576 // push indent
577 EM_pushlog();
579 // loop through and process each file
580 for( i = 1; i < argc; i++ )
582 // make sure
583 if( argv[i][0] == '-' || argv[i][0] == '+' )
585 if( !strcmp(argv[i], "--dump") || !strcmp(argv[i], "+d" ) )
586 compiler->emitter->dump = TRUE;
587 else if( !strcmp(argv[i], "--nodump") || !strcmp(argv[i], "-d" ) )
588 compiler->emitter->dump = FALSE;
589 else
590 get_count( argv[i], &count );
592 continue;
595 // parse out command line arguments
596 if( !extract_args( argv[i], filename, args ) )
598 // error
599 fprintf( stderr, "[chuck]: malformed filename with argument list...\n" );
600 fprintf( stderr, " --> '%s'", argv[i] );
601 return 1;
604 // log
605 EM_log( CK_LOG_FINE, "compiling '%s'...", filename.c_str() );
606 // push indent
607 EM_pushlog();
609 // parse, type-check, and emit
610 if( !compiler->go( filename, NULL ) )
611 return 1;
613 // get the code
614 code = compiler->output();
615 // name it
616 code->name += string(argv[i]);
618 // log
619 EM_log( CK_LOG_FINE, "sporking %d %s...", count,
620 count == 1 ? "instance" : "instances" );
622 // spork it
623 while( count-- )
625 // spork
626 shred = vm->spork( code, NULL );
627 // add args
628 shred->args = args;
631 // pop indent
632 EM_poplog();
634 // reset count
635 count = 1;
638 // pop indent
639 EM_poplog();
641 // reset the parser
642 reset_parse();
644 // boost priority
645 if( Chuck_VM::our_priority != 0x7fffffff )
647 // try
648 if( !Chuck_VM::set_priority( Chuck_VM::our_priority, vm ) )
650 // error
651 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
652 exit( 1 );
656 // server
657 if( enable_server )
659 // log
660 EM_log( CK_LOG_SYSTEM, "starting listener on port: %d...", g_port );
662 // start tcp server
663 g_sock = ck_tcp_create( 1 );
664 if( !g_sock || !ck_bind( g_sock, g_port ) || !ck_listen( g_sock, 10 ) )
666 fprintf( stderr, "[chuck]: cannot bind to tcp port %i...\n", g_port );
667 ck_close( g_sock );
668 g_sock = NULL;
670 else
672 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
673 pthread_create( &g_tid_otf, NULL, otf_cb, NULL );
674 #else
675 g_tid_otf = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)otf_cb, NULL, 0, 0 );
676 #endif
679 else
681 // log
682 EM_log( CK_LOG_SYSTEM, "OTF server/listener: OFF" );
685 // start shell on separate thread
686 if( enable_shell )
688 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
689 pthread_create( &g_tid_shell, NULL, shell_cb, g_shell );
690 #else
691 g_tid_shell = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)shell_cb, g_shell, 0, 0 );
692 #endif
695 // run the vm
696 vm->run();
698 // detach
699 all_detach();
701 // free vm
702 vm = NULL; SAFE_DELETE( g_vm );
703 // free the compiler
704 compiler = NULL; SAFE_DELETE( g_compiler );
706 // wait for the shell, if it is running
707 // does the VM reset its priority to normal before exiting?
708 if( enable_shell )
709 while( g_shell != NULL )
710 usleep(10000);
712 return 0;