*** empty log message ***
[chuck-blob.git] / v2 / chuck_main.cpp
blob5162f64a2d00faeba1fca0840c8cd5034879ba55
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_string.h"
52 #include "util_thread.h"
53 #include "util_network.h"
54 #include "hidio_sdl.h"
56 #include <signal.h>
57 #ifndef __PLATFORM_WIN32__
58 #include <unistd.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #endif
64 // global variables
65 #if defined(__MACOSX_CORE__)
66 t_CKINT g_priority = 80;
67 t_CKINT g_priority_low = 60;
68 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
69 t_CKINT g_priority = THREAD_PRIORITY_HIGHEST;
70 t_CKINT g_priority_low = THREAD_PRIORITY_HIGHEST;
71 #else
72 t_CKINT g_priority = 0x7fffffff;
73 t_CKINT g_priority_low = 0x7fffffff;
74 #endif
76 // thread id for otf thread
77 CHUCK_THREAD g_tid_otf = 0;
78 // thread id for shell
79 CHUCK_THREAD g_tid_shell = 0;
81 // default destination host name
82 char g_host[256] = "127.0.0.1";
87 //-----------------------------------------------------------------------------
88 // name: signal_int()
89 // desc: ...
90 //-----------------------------------------------------------------------------
91 extern "C" void signal_int( int sig_num )
93 fprintf( stderr, "[chuck]: cleaning up...\n" );
95 if( g_vm )
97 // get vm
98 Chuck_VM * vm = g_vm;
99 Chuck_Compiler * compiler = g_compiler;
100 // flag the global one
101 g_vm = NULL;
102 g_compiler = NULL;
103 // if not NULL
104 if( vm )
106 // stop
107 vm->stop();
108 // detach
109 all_detach();
112 // things don't work so good on windows...
113 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
114 // pthread_kill( g_tid_otf, 2 );
115 if( g_tid_otf ) pthread_cancel( g_tid_otf );
116 if( g_tid_whatever ) pthread_cancel( g_tid_whatever );
117 // if( g_tid_otf ) usleep( 50000 );
118 #else
119 // close handle
120 if( g_tid_otf ) CloseHandle( g_tid_otf );
121 #endif
122 // will this work for windows?
123 SAFE_DELETE( vm );
124 SAFE_DELETE( compiler );
126 // ck_close( g_sock );
129 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
130 // pthread_join( g_tid_otf, NULL );
131 #endif
133 exit(2);
139 //-----------------------------------------------------------------------------
140 // name: next_power_2()
141 // desc: ...
142 // thanks: to Niklas Werner / music-dsp
143 //-----------------------------------------------------------------------------
144 t_CKUINT next_power_2( t_CKUINT n )
146 t_CKUINT nn = n;
147 for( ; n &= n-1; nn = n );
148 return nn * 2;
154 //-----------------------------------------------------------------------------
155 // name: uh()
156 // desc: ...
157 //-----------------------------------------------------------------------------
158 void uh( )
160 // TODO: play white noise and/or sound effects
161 srand( time( NULL ) );
162 while( true )
164 int n = (int)(rand() / (float)RAND_MAX * poop_size);
165 printf( "%s\n", poop[n] );
166 usleep( (unsigned long)(rand() / (float)RAND_MAX * 2000000) );
173 //-----------------------------------------------------------------------------
174 // name: init_shell()
175 // desc: ...
176 //-----------------------------------------------------------------------------
177 t_CKBOOL init_shell( Chuck_Shell * shell, Chuck_Shell_UI * ui, Chuck_VM * vm )
179 // initialize shell UI
180 if( !ui->init() )
182 fprintf( stderr, "[chuck]: error starting shell UI...\n" );
183 return FALSE;
186 // initialize
187 if( !shell->init( vm, ui ) )
189 fprintf( stderr, "[chuck]: error starting shell...\n" );
190 return FALSE;
193 return TRUE;
199 //-----------------------------------------------------------------------------
200 // name: get_count()
201 // desc: ...
202 //-----------------------------------------------------------------------------
203 t_CKBOOL get_count( const char * arg, t_CKUINT * out )
205 // no comment
206 if( !strncmp( arg, "--", 2 ) ) arg += 2;
207 else if( !strncmp( arg, "-", 1 ) ) arg += 1;
208 else return FALSE;
210 // end of string
211 if( *arg == '\0' ) return FALSE;
212 // not digit
213 if( *arg < '0' || *arg > '9' ) return FALSE;
215 // number
216 *out = (t_CKUINT)atoi( arg );
218 return TRUE;
224 //-----------------------------------------------------------------------------
225 // name: version()
226 // desc: ...
227 //-----------------------------------------------------------------------------
228 void version()
230 fprintf( stderr, "\n" );
231 fprintf( stderr, "chuck version: %s\n", CK_VERSION );
232 #if defined(__PLATFORM_WIN32__)
233 fprintf( stderr, " exe target: microsoft win32\n" );
234 #elif defined(__WINDOWS_DS__)
235 fprintf( stderr, " exe target: microsoft win32 + cygwin\n" );
236 #elif defined(__LINUX_ALSA__)
237 fprintf( stderr, " exe target: linux (alsa)\n" );
238 #elif defined(__LINUX_OSS__)
239 fprintf( stderr, " exe target: linux (oss)\n" );
240 #elif defined(__LINUX_JACK__)
241 fprintf( stderr, " exe target: linux (jack)\n" );
242 #elif defined(__MACOSX_UB__)
243 fprintf( stderr, " exe target: mac os x : universal binary\n" );
244 #elif defined(__MACOSX_CORE__) && defined(__LITTLE_ENDIAN__)
245 fprintf( stderr, " exe target: mac os x : intel\n" );
246 #elif defined(__MACOSX_CORE__)
247 fprintf( stderr, " exe target: mac os x : powerpc\n" );
248 #else
249 fprintf( stderr, " exe target: uh... unknown\n" );
250 #endif
251 fprintf( stderr, " http://chuck.cs.princeton.edu/\n\n" );
257 //-----------------------------------------------------------------------------
258 // name: usage()
259 // desc: ...
260 //-----------------------------------------------------------------------------
261 void usage()
263 fprintf( stderr, "usage: chuck --[options|commands] [+-=^] file1 file2 file3 ...\n" );
264 fprintf( stderr, " [options] = halt|loop|audio|silent|dump|nodump|server|about|\n" );
265 fprintf( stderr, " srate<N>|bufsize<N>|bufnum<N>|dac<N>|adc<N>|\n" );
266 fprintf( stderr, " remote<hostname>|port<N>|verbose<N>|probe|\n" );
267 fprintf( stderr, " channels<N>|out<N>|in<N>|shell|empty|level<N>|\n" );
268 fprintf( stderr, " blocking|callback|deprecate:{stop|warn|ignore}\n" );
269 fprintf( stderr, " [commands] = add|remove|replace|remove.all|status|time|kill\n" );
270 fprintf( stderr, " [+-=^] = shortcuts for add, remove, replace, status\n" );
271 version();
277 //-----------------------------------------------------------------------------
278 // name: main()
279 // desc: entry point
280 //-----------------------------------------------------------------------------
281 int main( int argc, char ** argv )
283 Chuck_Compiler * compiler = NULL;
284 Chuck_VM * vm = NULL;
285 Chuck_VM_Code * code = NULL;
286 Chuck_VM_Shred * shred = NULL;
288 t_CKBOOL enable_audio = TRUE;
289 t_CKBOOL vm_halt = TRUE;
290 t_CKUINT srate = SAMPLING_RATE_DEFAULT;
291 t_CKUINT buffer_size = BUFFER_SIZE_DEFAULT;
292 t_CKUINT num_buffers = NUM_BUFFERS_DEFAULT;
293 t_CKUINT dac = 0;
294 t_CKUINT adc = 0;
295 t_CKUINT dac_chans = 2;
296 t_CKUINT adc_chans = 2;
297 t_CKBOOL dump = FALSE;
298 t_CKBOOL probe = FALSE;
299 t_CKBOOL set_priority = FALSE;
300 t_CKBOOL auto_depend = FALSE;
301 t_CKBOOL block = FALSE;
302 t_CKBOOL enable_shell = FALSE;
303 t_CKBOOL no_vm = FALSE;
304 t_CKBOOL load_hid = FALSE;
305 t_CKBOOL enable_server = TRUE;
306 t_CKBOOL do_watchdog = TRUE;
307 t_CKINT log_level = CK_LOG_CORE;
308 t_CKINT deprecate_level = 1; // warn
310 string filename = "";
311 vector<string> args;
313 #if defined(__MACOSX_CORE__)
314 do_watchdog = TRUE;
315 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
316 do_watchdog = TRUE;
317 #else
318 do_watchdog = FALSE;
319 #endif
321 t_CKUINT files = 0;
322 t_CKUINT count = 1;
323 t_CKINT i;
325 // set log level
326 EM_setlog( log_level );
328 // parse command line args
329 for( i = 1; i < argc; i++ )
331 if( argv[i][0] == '-' || argv[i][0] == '+' ||
332 argv[i][0] == '=' || argv[i][0] == '^' || argv[i][0] == '@' )
334 if( !strcmp(argv[i], "--dump") || !strcmp(argv[i], "+d")
335 || !strcmp(argv[i], "--nodump") || !strcmp(argv[i], "-d") )
336 continue;
337 else if( get_count( argv[i], &count ) )
338 continue;
339 else if( !strcmp(argv[i], "--audio") || !strcmp(argv[i], "-a") )
340 enable_audio = TRUE;
341 else if( !strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s") )
342 enable_audio = FALSE;
343 else if( !strcmp(argv[i], "--halt") || !strcmp(argv[i], "-t") )
344 vm_halt = TRUE;
345 else if( !strcmp(argv[i], "--loop") || !strcmp(argv[i], "-l") )
346 { vm_halt = FALSE; enable_server = TRUE; }
347 else if( !strcmp(argv[i], "--server") )
348 enable_server = TRUE;
349 else if( !strcmp(argv[i], "--standalone") )
350 enable_server = FALSE;
351 else if( !strcmp(argv[i], "--callback") )
352 block = FALSE;
353 else if( !strcmp(argv[i], "--blocking") )
354 block = TRUE;
355 else if( !strcmp(argv[i], "--hid") )
356 load_hid = TRUE;
357 else if( !strcmp(argv[i], "--shell") || !strcmp( argv[i], "-e" ) )
358 { enable_shell = TRUE; vm_halt = FALSE; }
359 else if( !strcmp(argv[i], "--empty") )
360 no_vm = TRUE;
361 else if( !strncmp(argv[i], "--srate", 7) )
362 srate = atoi( argv[i]+7 ) > 0 ? atoi( argv[i]+7 ) : srate;
363 else if( !strncmp(argv[i], "-r", 2) )
364 srate = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : srate;
365 else if( !strncmp(argv[i], "--bufsize", 9) )
366 buffer_size = atoi( argv[i]+9 ) > 0 ? atoi( argv[i]+9 ) : buffer_size;
367 else if( !strncmp(argv[i], "-b", 2) )
368 buffer_size = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : buffer_size;
369 else if( !strncmp(argv[i], "--bufnum", 8) )
370 num_buffers = atoi( argv[i]+8 ) > 0 ? atoi( argv[i]+8 ) : num_buffers;
371 else if( !strncmp(argv[i], "-n", 2) )
372 num_buffers = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : num_buffers;
373 else if( !strncmp(argv[i], "--dac", 5) )
374 dac = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 0;
375 else if( !strncmp(argv[i], "--adc", 5) )
376 adc = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 0;
377 else if( !strncmp(argv[i], "--channels", 10) )
378 dac_chans = adc_chans = atoi( argv[i]+10 ) > 0 ? atoi( argv[i]+10 ) : 2;
379 else if( !strncmp(argv[i], "-c", 2) )
380 dac_chans = adc_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
381 else if( !strncmp(argv[i], "--out", 5) )
382 dac_chans = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 2;
383 else if( !strncmp(argv[i], "-o", 2) )
384 dac_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
385 else if( !strncmp(argv[i], "--in", 4) )
386 adc_chans = atoi( argv[i]+4 ) > 0 ? atoi( argv[i]+4 ) : 2;
387 else if( !strncmp(argv[i], "-i", 2) )
388 adc_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
389 else if( !strncmp(argv[i], "--level", 7) )
390 { g_priority = atoi( argv[i]+7 ); set_priority = TRUE; }
391 else if( !strncmp(argv[i], "--watchdog", 10) )
392 { g_watchdog_timeout = atof( argv[i]+10 );
393 if( g_watchdog_timeout <= 0 ) g_watchdog_timeout = 0.5;
394 do_watchdog = TRUE; }
395 else if( !strncmp(argv[i], "--nowatchdog", 12) )
396 do_watchdog = FALSE;
397 else if( !strncmp(argv[i], "--remote", 8) )
398 strcpy( g_host, argv[i]+8 );
399 else if( !strncmp(argv[i], "@", 1) )
400 strcpy( g_host, argv[i]+1 );
401 else if( !strncmp(argv[i], "--port", 6) )
402 g_port = atoi( argv[i]+6 );
403 else if( !strncmp(argv[i], "-p", 2) )
404 g_port = atoi( argv[i]+2 );
405 else if( !strncmp(argv[i], "--auto", 6) )
406 auto_depend = TRUE;
407 else if( !strncmp(argv[i], "-u", 2) )
408 auto_depend = TRUE;
409 else if( !strncmp(argv[i], "--log", 5) )
410 log_level = argv[i][5] ? atoi( argv[i]+5 ) : CK_LOG_INFO;
411 else if( !strncmp(argv[i], "--verbose", 9) )
412 log_level = argv[i][9] ? atoi( argv[i]+9 ) : CK_LOG_INFO;
413 else if( !strncmp(argv[i], "-v", 2) )
414 log_level = argv[i][2] ? atoi( argv[i]+2 ) : CK_LOG_INFO;
415 else if( !strncmp(argv[i], "--deprecate", 11) )
417 // get the rest
418 string arg = argv[i]+11;
419 if( arg == ":stop" ) deprecate_level = 0;
420 else if( arg == ":warn" ) deprecate_level = 1;
421 else if( arg == ":ignore" ) deprecate_level = 2;
422 else
424 // error
425 fprintf( stderr, "[chuck]: invalid arguments for '--deprecate'...\n" );
426 fprintf( stderr, "[chuck]: ... (looking for :stop, :warn, or :ignore)\n" );
427 exit( 1 );
430 else if( !strcmp( argv[i], "--probe" ) )
431 probe = TRUE;
432 else if( !strcmp( argv[i], "--poop" ) )
433 uh();
434 else if( !strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")
435 || !strcmp(argv[i], "--about") )
437 usage();
438 exit( 2 );
440 else if( !strcmp( argv[i], "--version" ) )
442 version();
443 exit( 2 );
445 else
447 // boost log level
448 g_otf_log = CK_LOG_CORE;
449 // flag
450 int is_otf = FALSE;
451 // log level
452 EM_setlog( log_level );
453 // do it
454 if( otf_send_cmd( argc, argv, i, g_host, g_port, &is_otf ) )
455 exit( 0 );
457 // is otf
458 if( is_otf ) exit( 1 );
460 // done
461 fprintf( stderr, "[chuck]: invalid flag '%s'\n", argv[i] );
462 usage();
463 exit( 1 );
466 else
467 files++;
470 // log level
471 EM_setlog( log_level );
473 // probe
474 if( probe )
476 Digitalio::probe();
478 EM_error2b( 0, "" );
479 probeMidiIn();
480 EM_error2b( 0, "" );
481 probeMidiOut();
482 EM_error2b( 0, "" );
484 //HidInManager::probeHidIn();
486 // exit
487 exit( 0 );
490 // check buffer size
491 buffer_size = next_power_2( buffer_size-1 );
492 // check mode and blocking
493 if( !enable_audio && !block ) block = TRUE;
494 // audio, boost
495 if( !set_priority && !block ) g_priority = g_priority_low;
496 if( !set_priority && !enable_audio ) g_priority = 0x7fffffff;
497 // set priority
498 Chuck_VM::our_priority = g_priority;
499 // set watchdog
500 g_do_watchdog = do_watchdog;
502 if ( !files && vm_halt && !enable_shell )
504 fprintf( stderr, "[chuck]: no input files... (try --help)\n" );
505 exit( 1 );
508 // shell initialization without vm
509 if( enable_shell && no_vm )
511 // instantiate
512 g_shell = new Chuck_Shell;
513 // initialize
514 if( !init_shell( g_shell, new Chuck_Console, NULL ) )
515 exit( 1 );
516 // no vm is needed, just start running the shell now
517 g_shell->run();
518 // clean up
519 SAFE_DELETE( g_shell );
520 // done
521 exit( 0 );
524 // make sure vm
525 if( no_vm )
527 fprintf( stderr, "[chuck]: '--empty' can only be used with shell...\n" );
528 exit( 1 );
531 // allocate the vm - needs the type system
532 vm = g_vm = new Chuck_VM;
533 if( !vm->initialize( enable_audio, vm_halt, srate, buffer_size,
534 num_buffers, dac, adc, dac_chans, adc_chans, block ) )
536 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
537 exit( 1 );
540 // allocate the compiler
541 compiler = g_compiler = new Chuck_Compiler;
542 // initialize the compiler
543 if( !compiler->initialize( vm ) )
545 fprintf( stderr, "[chuck]: error initializing compiler...\n" );
546 exit( 1 );
548 // enable dump
549 compiler->emitter->dump = dump;
550 // set auto depend
551 compiler->set_auto_depend( auto_depend );
553 // vm synthesis subsystem - needs the type system
554 if( !vm->initialize_synthesis( ) )
556 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
557 exit( 1 );
560 // pre-load hid
561 if( load_hid ) HidInManager::init();
563 // catch SIGINT
564 signal( SIGINT, signal_int );
565 #ifndef __PLATFORM_WIN32__
566 // catch SIGPIPE
567 signal( SIGPIPE, signal_pipe );
568 #endif
570 // shell initialization
571 if( enable_shell )
573 // instantiate
574 g_shell = new Chuck_Shell;
575 // initialize
576 if( !init_shell( g_shell, new Chuck_Console, vm ) )
577 exit( 1 );
580 // set deprecate
581 compiler->env->deprecate_level = deprecate_level;
583 // reset count
584 count = 1;
586 // log
587 EM_log( CK_LOG_SEVERE, "starting compilation..." );
588 // push indent
589 EM_pushlog();
591 // loop through and process each file
592 for( i = 1; i < argc; i++ )
594 // make sure
595 if( argv[i][0] == '-' || argv[i][0] == '+' )
597 if( !strcmp(argv[i], "--dump") || !strcmp(argv[i], "+d" ) )
598 compiler->emitter->dump = TRUE;
599 else if( !strcmp(argv[i], "--nodump") || !strcmp(argv[i], "-d" ) )
600 compiler->emitter->dump = FALSE;
601 else
602 get_count( argv[i], &count );
604 continue;
607 // parse out command line arguments
608 if( !extract_args( argv[i], filename, args ) )
610 // error
611 fprintf( stderr, "[chuck]: malformed filename with argument list...\n" );
612 fprintf( stderr, " --> '%s'", argv[i] );
613 return 1;
616 // log
617 EM_log( CK_LOG_FINE, "compiling '%s'...", filename.c_str() );
618 // push indent
619 EM_pushlog();
621 // parse, type-check, and emit
622 if( !compiler->go( filename, NULL ) )
623 return 1;
625 // get the code
626 code = compiler->output();
627 // name it
628 code->name += string(argv[i]);
630 // log
631 EM_log( CK_LOG_FINE, "sporking %d %s...", count,
632 count == 1 ? "instance" : "instances" );
634 // spork it
635 while( count-- )
637 // spork
638 shred = vm->spork( code, NULL );
639 // add args
640 shred->args = args;
643 // pop indent
644 EM_poplog();
646 // reset count
647 count = 1;
650 // pop indent
651 EM_poplog();
653 // reset the parser
654 reset_parse();
656 // boost priority
657 if( Chuck_VM::our_priority != 0x7fffffff )
659 // try
660 if( !Chuck_VM::set_priority( Chuck_VM::our_priority, vm ) )
662 // error
663 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
664 exit( 1 );
668 // server
669 if( enable_server )
671 // log
672 EM_log( CK_LOG_SYSTEM, "starting listener on port: %d...", g_port );
674 // start tcp server
675 g_sock = ck_tcp_create( 1 );
676 if( !g_sock || !ck_bind( g_sock, g_port ) || !ck_listen( g_sock, 10 ) )
678 fprintf( stderr, "[chuck]: cannot bind to tcp port %i...\n", g_port );
679 ck_close( g_sock );
680 g_sock = NULL;
682 else
684 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
685 pthread_create( &g_tid_otf, NULL, otf_cb, NULL );
686 #else
687 g_tid_otf = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)otf_cb, NULL, 0, 0 );
688 #endif
691 else
693 // log
694 EM_log( CK_LOG_SYSTEM, "OTF server/listener: OFF" );
697 // start shell on separate thread
698 if( enable_shell )
700 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
701 pthread_create( &g_tid_shell, NULL, shell_cb, g_shell );
702 #else
703 g_tid_shell = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)shell_cb, g_shell, 0, 0 );
704 #endif
707 // run the vm
708 vm->run();
710 // detach
711 all_detach();
713 // free vm
714 vm = NULL; SAFE_DELETE( g_vm );
715 // free the compiler
716 compiler = NULL; SAFE_DELETE( g_compiler );
718 // wait for the shell, if it is running
719 // does the VM reset its priority to normal before exiting?
720 if( enable_shell )
721 while( g_shell != NULL )
722 usleep(10000);
724 return 0;