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
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
29 // authors: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
32 //-----------------------------------------------------------------------------
34 #include "chuck_instr.h"
35 #include "chuck_bbq.h"
36 #include "chuck_errmsg.h"
38 #include "chuck_type.h"
39 #include "chuck_globals.h"
40 #include "chuck_lang.h"
46 #if defined(__PLATFORM_WIN32__)
56 //-----------------------------------------------------------------------------
57 // name: struct Chuck_VM_Frame
59 //-----------------------------------------------------------------------------
66 Chuck_VM_Frame() { size
= 0; }
73 //-----------------------------------------------------------------------------
74 // name: struct Chuck_VM_Func
76 //-----------------------------------------------------------------------------
81 Chuck_VM_Frame
* frame
;
85 Chuck_VM_Func() { code
= NULL
; frame
= NULL
; index
= 0; }
92 //-----------------------------------------------------------------------------
93 // name: struct Chuck_VM_FTable
94 // desc: function table
95 //-----------------------------------------------------------------------------
96 struct Chuck_VM_FTable
103 Chuck_VM_Func
* get_func( t_CKUINT index
);
104 t_CKUINT
append( Chuck_VM_Func
* f
);
105 t_CKBOOL
remove( t_CKUINT index
);
108 vector
<Chuck_VM_Func
*> func_table
;
114 //-----------------------------------------------------------------------------
117 //-----------------------------------------------------------------------------
123 m_num_dumped_shreds
= 0;
125 m_reply_buffer
= NULL
;
126 m_event_buffer
= NULL
;
133 m_audio_started
= FALSE
;
137 m_num_dac_channels
= 0;
138 m_num_adc_channels
= 0;
145 //-----------------------------------------------------------------------------
148 //-----------------------------------------------------------------------------
149 Chuck_VM::~Chuck_VM()
151 if( m_init
) shutdown();
158 //UGEN_TICK __dac_tick( Chuck_Object * SELF, SAMPLE in, SAMPLE * out )
159 //{ *out = in; return TRUE; }
160 //UGEN_TICK __bunghole_tick( Chuck_Object * SELF, SAMPLE in, SAMPLE * out )
161 //{ *out = 0.0f; return TRUE; }
165 #ifdef __MACOSX_CORE__
166 t_CKINT
Chuck_VM::our_priority
= 85;
168 t_CKINT
Chuck_VM::our_priority
= 0x7fffffff;
172 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
173 //-----------------------------------------------------------------------------
174 // name: set_priority()
176 //-----------------------------------------------------------------------------
177 t_CKBOOL
Chuck_VM::set_priority( t_CKINT priority
, Chuck_VM
* vm
)
179 struct sched_param param
;
180 pthread_t tid
= pthread_self();
184 EM_log( CK_LOG_INFO
, "setting thread priority to: %ld...", priority
);
187 if( pthread_getschedparam( tid
, &policy
, ¶m
) )
190 vm
->m_last_error
= "could not get current scheduling parameters";
195 param
.sched_priority
= priority
;
199 if( pthread_setschedparam( tid
, policy
, ¶m
) )
202 vm
->m_last_error
= "could not set new scheduling parameters";
209 //-----------------------------------------------------------------------------
210 // name: set_priority()
212 //-----------------------------------------------------------------------------
213 t_CKBOOL
Chuck_VM::set_priority( t_CKINT priority
, Chuck_VM
* vm
)
215 // if priority is 0 then done
216 if( !priority
) return TRUE
;
218 // set the priority class of the process
219 // if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
223 EM_log( CK_LOG_INFO
, "setting thread priority to: %ld...", priority
);
225 // set the priority the thread
226 // if( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ) )
227 if( !SetThreadPriority( GetCurrentThread(), priority
) )
230 vm
->m_last_error
= "could not set new scheduling parameters";
241 //-----------------------------------------------------------------------------
242 // name: initialize()
244 //-----------------------------------------------------------------------------
245 t_CKBOOL
Chuck_VM::initialize( t_CKBOOL enable_audio
, t_CKBOOL halt
, t_CKUINT srate
,
246 t_CKUINT buffer_size
, t_CKUINT num_buffers
,
247 t_CKUINT dac
, t_CKUINT adc
, t_CKUINT dac_chan
,
248 t_CKUINT adc_chan
, t_CKBOOL block
, t_CKUINT adaptive
)
252 m_last_error
= "VM already initialized!";
256 // boost thread priority
257 // if( priority != 0x7fffffff && !set_priority( priority, this ) )
261 EM_log( CK_LOG_SYSTEM
, "initializing virtual machine..." );
262 EM_pushlog(); // push stack
263 EM_log( CK_LOG_SYSTEM
, "behavior: %s", halt
? "HALT" : "LOOP" );
266 Chuck_VM_Object::lock_all();
271 m_audio
= enable_audio
;
275 EM_log( CK_LOG_SYSTEM
, "allocating shreduler..." );
276 // allocate shreduler
277 m_shreduler
= new Chuck_VM_Shreduler
;
278 m_shreduler
->bbq
= m_bbq
;
279 m_shreduler
->rt_audio
= enable_audio
;
280 m_shreduler
->set_adaptive( adaptive
> 0 ? adaptive
: 0 );
283 EM_log( CK_LOG_SYSTEM
, "allocating messaging buffers..." );
284 // allocate msg buffer
285 m_msg_buffer
= new CBufferSimple
;
286 m_msg_buffer
->initialize( 1024, sizeof(Chuck_Msg
*) );
287 //m_msg_buffer->join(); // this should return 0
288 m_reply_buffer
= new CBufferSimple
;
289 m_reply_buffer
->initialize( 1024, sizeof(Chuck_Msg
*) );
290 //m_reply_buffer->join(); // this should return 0 too
291 m_event_buffer
= new CBufferSimple
;
292 m_event_buffer
->initialize( 1024, sizeof(Chuck_Event
*) );
293 //m_event_buffer->join(); // this should also return 0
296 EM_log( CK_LOG_SYSTEM
, "real-time audio: %s", enable_audio
? "YES" : "NO" );
297 EM_log( CK_LOG_SYSTEM
, "mode: %s", block
? "BLOCKING" : "CALLBACK" );
298 EM_log( CK_LOG_SYSTEM
, "sample rate: %ld", srate
);
299 EM_log( CK_LOG_SYSTEM
, "buffer size: %ld", buffer_size
);
302 EM_log( CK_LOG_SYSTEM
, "num buffers: %ld", num_buffers
);
303 EM_log( CK_LOG_SYSTEM
, "devices adc: %ld dac: %d (default 0)", adc
, dac
);
304 EM_log( CK_LOG_SYSTEM
, "adaptive block processing: %ld", adaptive
> 1 ? adaptive
: 0 );
306 EM_log( CK_LOG_SYSTEM
, "channels in: %ld out: %ld", adc_chan
, dac_chan
);
307 m_num_adc_channels
= adc_chan
;
308 m_num_dac_channels
= dac_chan
;
310 // at least set the sample rate and buffer size
311 m_bbq
->set_srate( srate
);
312 m_bbq
->set_bufsize( buffer_size
);
313 m_bbq
->set_numbufs( num_buffers
);
314 m_bbq
->set_inouts( adc
, dac
);
315 m_bbq
->set_chans( adc_chan
, dac_chan
);
320 // TODO: clean up all the dynamic objects here on failure
321 // and in the shutdown function!
323 return m_init
= TRUE
;
329 //-----------------------------------------------------------------------------
330 // name: initialize_synthesis()
331 // desc: requires type system
332 //-----------------------------------------------------------------------------
333 t_CKBOOL
Chuck_VM::initialize_synthesis( )
337 m_last_error
= "VM initialize_synthesis() called on raw VM";
341 if( !g_t_dac
|| !g_t_adc
)
343 m_last_error
= "VM initialize_synthesis() called before type system initialized";
349 m_last_error
= "VM synthesis already initialized";
354 EM_log( CK_LOG_SYSTEM
, "initializing synthesis engine..." );
359 EM_log( CK_LOG_SEVERE
, "initializing 'dac'..." );
360 // allocate dac and adc
361 g_t_dac
->ugen_info
->num_outs
=
362 g_t_dac
->ugen_info
->num_ins
= m_num_dac_channels
;
363 m_dac
= (Chuck_UGen
*)instantiate_and_initialize_object( g_t_dac
, NULL
);
364 object_ctor( m_dac
, NULL
, NULL
); // TODO: this can't be the place to do this
365 stereo_ctor( m_dac
, NULL
, NULL
); // TODO: is the NULL shred a problem?
366 multi_ctor( m_dac
, NULL
, NULL
); // TODO: remove and let type system do this
372 EM_log( CK_LOG_SEVERE
, "initializing 'adc'..." );
373 g_t_adc
->ugen_info
->num_ins
=
374 g_t_adc
->ugen_info
->num_outs
= m_num_adc_channels
;
375 m_adc
= (Chuck_UGen
*)instantiate_and_initialize_object( g_t_adc
, NULL
);
376 object_ctor( m_adc
, NULL
, NULL
); // TODO: this can't be the place to do this
377 stereo_ctor( m_adc
, NULL
, NULL
);
378 multi_ctor( m_adc
, NULL
, NULL
); // TODO: remove and let type system do this
384 EM_log( CK_LOG_SEVERE
, "initializing 'blackhole'..." );
385 m_bunghole
= new Chuck_UGen
;
386 m_bunghole
->add_ref();
388 initialize_object( m_bunghole
, &t_ugen
);
389 m_bunghole
->tick
= NULL
;
390 m_bunghole
->alloc_v( m_shreduler
->m_max_block_size
);
391 m_shreduler
->m_dac
= m_dac
;
392 m_shreduler
->m_adc
= m_adc
;
393 m_shreduler
->m_bunghole
= m_bunghole
;
394 m_shreduler
->m_num_dac_channels
= m_num_dac_channels
;
395 m_shreduler
->m_num_adc_channels
= m_num_adc_channels
;
398 EM_log( CK_LOG_SYSTEM
, "initializing '%s' audio...", m_audio
? "real-time" : "fake-time" );
400 if( !m_bbq
->initialize( m_num_dac_channels
, m_num_adc_channels
,
401 Digitalio::m_sampling_rate
, 16,
402 Digitalio::m_buffer_size
, Digitalio::m_num_buffers
,
403 Digitalio::m_dac_n
, Digitalio::m_adc_n
,
404 m_block
, this, m_audio
) )
406 m_last_error
= "cannot initialize audio device (try using --silent/-s)";
421 //-----------------------------------------------------------------------------
422 // name: compensate_bbq()
424 //-----------------------------------------------------------------------------
425 void Chuck_VM::compensate_bbq()
427 // set shreduler - the audio was initialized elsewhere
428 m_shreduler
->bbq
= m_bbq
;
434 //-----------------------------------------------------------------------------
437 //-----------------------------------------------------------------------------
438 t_CKBOOL
Chuck_VM::shutdown()
440 // make sure we are in the initialized state
441 if( !m_init
) return FALSE
;
444 EM_log( CK_LOG_SYSTEM
, "shutting down virtual machine..." );
448 Chuck_VM_Object::unlock_all();
461 EM_log( CK_LOG_SYSTEM
, "shutting down real-time audio..." );
463 m_bbq
->digi_out()->cleanup();
464 m_bbq
->digi_in()->cleanup();
469 EM_log( CK_LOG_SYSTEM
, "freeing bbq subsystem..." );
471 SAFE_DELETE( m_bbq
);
474 EM_log( CK_LOG_SYSTEM
, "freeing shreduler..." );
475 // free the shreduler
476 SAFE_DELETE( m_shreduler
);
479 EM_log( CK_LOG_SYSTEM
, "freeing msg/reply/event buffers..." );
480 // free the msg buffer
481 SAFE_DELETE( m_msg_buffer
);
482 // free the reply buffer
483 SAFE_DELETE( m_reply_buffer
);
484 // free the event buffer
485 SAFE_DELETE( m_event_buffer
);
488 EM_log( CK_LOG_SEVERE
, "clearing shreds..." );
490 Chuck_VM_Shred
* curr
= m_shreds
, * prev
= NULL
;
503 EM_log( CK_LOG_SEVERE
, "freeing dumped shreds..." );
505 this->release_dump();
509 EM_log( CK_LOG_SYSTEM
, "freeing special ugens..." );
511 SAFE_RELEASE( m_dac
);
512 SAFE_RELEASE( m_adc
);
513 SAFE_RELEASE( m_bunghole
);
526 //-----------------------------------------------------------------------------
527 // name: start_audio()
529 //-----------------------------------------------------------------------------
530 t_CKBOOL
Chuck_VM::start_audio( )
533 if( !m_audio_started
&& m_audio
)
535 EM_log( CK_LOG_SEVERE
, "starting real-time audio..." );
536 m_bbq
->digi_out()->start();
537 m_bbq
->digi_in()->start();
540 // set the flag to true to avoid entering this function
541 m_audio_started
= TRUE
;
549 //-----------------------------------------------------------------------------
552 //-----------------------------------------------------------------------------
553 t_CKBOOL
Chuck_VM::run( )
558 m_last_error
= "VM and/or synthesis not initialized...";
562 // check if already running
565 m_last_error
= "virtual machine already running...";
572 EM_log( CK_LOG_SYSTEM
, "running virtual machine..." );
580 EM_log( CK_LOG_SEVERE
, "initializing audio buffers..." );
581 if( !m_bbq
->digi_out()->initialize( ) )
583 m_last_error
= "cannot open audio output (option: use --silent/-s)";
587 m_bbq
->digi_in()->initialize( );
591 EM_log( CK_LOG_SEVERE
, "virtual machine running..." );
596 if( m_block
) this->run( -1 );
599 // compute shreds before first sample
605 EM_log( CK_LOG_SYSTEM
, "virtual machine stopped..." );
610 if( !m_audio_started
) start_audio();
621 /*should we comment out what we just did?
622 i can't think of why it might be affecting this part of the vm
629 //-----------------------------------------------------------------------------
632 //-----------------------------------------------------------------------------
633 t_CKBOOL
Chuck_VM::compute()
635 Chuck_VM_Shred
*& shred
= m_shreduler
->m_current_shred
;
636 Chuck_Msg
* msg
= NULL
;
637 Chuck_Event
* event
= NULL
;
638 t_CKBOOL iterate
= TRUE
;
640 // iteration until no more shreds/events/messages
643 // get the shreds queued for 'now'
644 while(( shred
= m_shreduler
->get() ))
646 // set the current time of the shred
647 shred
->now
= shred
->wake_time
;
649 // track shred activation
650 CK_TRACK( Chuck_Stats::instance()->activate_shred( shred
) );
653 if( !shred
->run( this ) )
655 // track shred deactivation
656 CK_TRACK( Chuck_Stats::instance()->deactivate_shred( shred
) );
658 this->free( shred
, TRUE
);
660 if( !m_num_shreds
&& m_halt
) return FALSE
;
663 // track shred deactivation
664 CK_TRACK( if( shred
) Chuck_Stats::instance()->deactivate_shred( shred
) );
670 // set to false for now
673 // broadcast queued events
674 while( m_event_buffer
->get( &event
, 1 ) )
675 { event
->broadcast(); iterate
= TRUE
; }
678 while( m_msg_buffer
->get( &msg
, 1 ) )
679 { process_msg( msg
); iterate
= TRUE
; }
681 // clear dumped shreds
682 if( m_num_dumped_shreds
> 0 )
692 //-----------------------------------------------------------------------------
695 //-----------------------------------------------------------------------------
696 t_CKBOOL
Chuck_VM::run( t_CKINT num_samps
)
702 if( !compute() ) goto vm_stop
;
705 if( !m_audio_started
) start_audio();
707 // advance the shreduler
708 if( !m_shreduler
->m_adaptive
)
710 m_shreduler
->advance();
711 if( num_samps
> 0 ) num_samps
--;
713 else m_shreduler
->advance_v( num_samps
);
723 EM_log( CK_LOG_SYSTEM
, "virtual machine stopped..." );
731 //-----------------------------------------------------------------------------
734 //-----------------------------------------------------------------------------
735 t_CKBOOL
Chuck_VM::pause( )
745 //-----------------------------------------------------------------------------
748 //-----------------------------------------------------------------------------
749 t_CKBOOL
Chuck_VM::stop( )
752 EM_log( CK_LOG_SEVERE
, "requesting STOP virtual machine..." );
755 Digitalio::m_end
= TRUE
;
763 //-----------------------------------------------------------------------------
766 //-----------------------------------------------------------------------------
767 void Chuck_VM::gc( t_CKUINT amount
)
774 //-----------------------------------------------------------------------------
777 //-----------------------------------------------------------------------------
785 //-----------------------------------------------------------------------------
788 //-----------------------------------------------------------------------------
789 t_CKBOOL
Chuck_VM::queue_msg( Chuck_Msg
* msg
, int count
)
791 assert( count
== 1 );
792 m_msg_buffer
->put( &msg
, count
);
799 //-----------------------------------------------------------------------------
800 // name: queue_event()
802 //-----------------------------------------------------------------------------
803 t_CKBOOL
Chuck_VM::queue_event( Chuck_Event
* event
, int count
)
805 assert( count
== 1 );
806 m_event_buffer
->put( &event
, count
);
813 //-----------------------------------------------------------------------------
816 //-----------------------------------------------------------------------------
817 Chuck_Msg
* Chuck_VM::get_reply( )
819 Chuck_Msg
* msg
= NULL
;
820 m_reply_buffer
->get( &msg
, 1 );
827 //-----------------------------------------------------------------------------
828 // name: process_msg()
830 //-----------------------------------------------------------------------------
831 t_CKUINT
Chuck_VM::process_msg( Chuck_Msg
* msg
)
833 t_CKUINT retval
= 0xfffffff0;
835 if( msg
->type
== MSG_REPLACE
)
837 Chuck_VM_Shred
* out
= m_shreduler
->lookup( msg
->param
);
840 EM_error3( "[chuck](VM): error replacing shred: no shred with id %i...",
846 Chuck_VM_Shred
* shred
= msg
->shred
;
849 shred
= new Chuck_VM_Shred
;
850 shred
->initialize( msg
->code
);
851 shred
->name
= msg
->code
->name
;
852 shred
->base_ref
= shred
->mem
;
855 // set the current time
856 shred
->start
= m_shreduler
->now_system
;
858 shred
->xid
= msg
->param
;
860 shred
->now
= shred
->wake_time
= m_shreduler
->now_system
;
862 shred
->vm_ref
= this;
864 if( msg
->args
) shred
->args
= *(msg
->args
);
865 // add it to the parent
867 shred
->parent
->children
[shred
->xid
] = shred
;
870 if( m_shreduler
->remove( out
) && m_shreduler
->shredule( shred
) )
872 EM_error3( "[chuck](VM): replacing shred %i (%s) with %i (%s)...",
873 out
->xid
, mini(out
->name
.c_str()), shred
->xid
, mini(shred
->name
.c_str()) );
874 this->free( out
, TRUE
, FALSE
);
877 // tracking new shred
878 CK_TRACK( Chuck_Stats::instance()->add_shred( shred
) );
884 EM_error3( "[chuck](VM): shreduler ERROR replacing shred %i...",
891 else if( msg
->type
== MSG_REMOVE
)
893 if( msg
->param
== 0xffffffff )
895 if( !this->m_num_shreds
)
897 EM_error3( "[chuck](VM): no shreds to remove..." );
902 t_CKINT xid
= m_shred_id
;
903 Chuck_VM_Shred
* shred
= NULL
;
904 while( xid
>= 0 && m_shreduler
->remove( shred
= m_shreduler
->lookup( xid
) ) == 0 )
908 EM_error3( "[chuck](VM): removing recent shred: %i (%s)...",
909 xid
, mini(shred
->name
.c_str()) );
910 this->free( shred
, TRUE
);
915 EM_error3( "[chuck](VM): no shreds removed..." );
922 Chuck_VM_Shred
* shred
= m_shreduler
->lookup( msg
->param
);
925 EM_error3( "[chuck](VM): cannot remove: no shred with id %i...",
930 if( shred
!= m_shreduler
->m_current_shred
&& !m_shreduler
->remove( shred
) ) // was lookup
932 EM_error3( "[chuck](VM): shreduler: cannot remove shred %i...",
937 EM_error3( "[chuck](VM): removing shred: %i (%s)...",
938 msg
->param
, mini(shred
->name
.c_str()) );
939 this->free( shred
, TRUE
);
943 else if( msg
->type
== MSG_REMOVEALL
)
945 t_CKUINT xid
= m_shred_id
;
946 EM_error3( "[chuck](VM): removing all (%i) shreds...", m_num_shreds
);
947 Chuck_VM_Shred
* shred
= NULL
;
949 while( m_num_shreds
&& xid
> 0 )
951 if( m_shreduler
->remove( shred
= m_shreduler
->lookup( xid
) ) )
952 this->free( shred
, TRUE
);
959 else if( msg
->type
== MSG_ADD
)
962 Chuck_VM_Shred
* shred
= NULL
;
963 if( msg
->shred
) shred
= this->spork( msg
->shred
);
964 else shred
= this->spork( msg
->code
, NULL
);
966 if( msg
->args
) shred
->args
= *(msg
->args
);
968 const char * s
= ( msg
->shred
? msg
->shred
->name
.c_str() : msg
->code
->name
.c_str() );
969 EM_error3( "[chuck](VM): sporking incoming shred: %i (%s)...", xid
, mini(s
) );
973 else if( msg
->type
== MSG_KILL
)
975 EM_error3( "[chuck](VM): KILL received...." );
976 // close file handles and clean up
978 // TODO: free more memory?
981 EM_log( CK_LOG_INFO
, "(VM): exiting..." );
985 else if( msg
->type
== MSG_STATUS
)
988 if( msg
->user
&& msg
->reply
)
991 Chuck_VM_Status
* status
= (Chuck_VM_Status
*)msg
->user
;
993 m_shreduler
->status( status
);
997 m_shreduler
->status();
1000 else if( msg
->type
== MSG_TIME
)
1002 float srate
= (float)Digitalio::sampling_rate();
1003 fprintf( stderr
, "[chuck](VM): the values of now:\n" );
1004 fprintf( stderr
, " now = %.6f (samp)\n", m_shreduler
->now_system
);
1005 fprintf( stderr
, " = %.6f (second)\n", m_shreduler
->now_system
/ srate
);
1006 fprintf( stderr
, " = %.6f (minute)\n", m_shreduler
->now_system
/ srate
/ 60.0f
);
1007 fprintf( stderr
, " = %.6f (hour)\n", m_shreduler
->now_system
/ srate
/ 60.0f
/ 60.0f
);
1008 fprintf( stderr
, " = %.6f (day)\n", m_shreduler
->now_system
/ srate
/ 60.0f
/ 60.0f
/ 24.0f
);
1009 fprintf( stderr
, " = %.6f (week)\n", m_shreduler
->now_system
/ srate
/ 60.0f
/ 60.0f
/ 24.0f
/ 7.0f
);
1011 else if( msg
->type
== MSG_RESET_ID
)
1013 t_CKUINT n
= m_shreduler
->highest();
1015 fprintf( stderr
, "[chuck](VM): reseting shred id to %d...\n", m_shred_id
+ 1 );
1022 msg
->replyA
= retval
;
1023 m_reply_buffer
->put( &msg
, 1 );
1034 //-----------------------------------------------------------------------------
1037 //-----------------------------------------------------------------------------
1038 t_CKUINT
Chuck_VM::next_id( )
1040 return ++m_shred_id
;
1046 //-----------------------------------------------------------------------------
1047 // name: shreduler()
1049 //-----------------------------------------------------------------------------
1050 Chuck_VM_Shreduler
* Chuck_VM::shreduler( ) const
1058 //-----------------------------------------------------------------------------
1061 //-----------------------------------------------------------------------------
1062 BBQ
* Chuck_VM::bbq( ) const
1070 //-----------------------------------------------------------------------------
1073 //-----------------------------------------------------------------------------
1074 t_CKUINT
Chuck_VM::srate() const
1076 return (t_CKUINT
)Digitalio::sampling_rate();
1082 //-----------------------------------------------------------------------------
1085 //-----------------------------------------------------------------------------
1086 Chuck_VM_Shred
* Chuck_VM::fork( Chuck_VM_Code
* code
)
1094 //-----------------------------------------------------------------------------
1097 //-----------------------------------------------------------------------------
1098 Chuck_VM_Shred
* Chuck_VM::spork( Chuck_VM_Code
* code
, Chuck_VM_Shred
* parent
)
1100 // allocate a new shred
1101 Chuck_VM_Shred
* shred
= new Chuck_VM_Shred
;
1102 // initialize the shred (default stack size)
1103 shred
->initialize( code
);
1105 shred
->name
= code
->name
;
1107 shred
->parent
= parent
;
1108 // set the base ref for global
1109 if( parent
) shred
->base_ref
= shred
->parent
->base_ref
;
1110 else shred
->base_ref
= shred
->mem
;
1112 this->spork( shred
);
1115 CK_TRACK( Chuck_Stats::instance()->add_shred( shred
) );
1123 //-----------------------------------------------------------------------------
1126 //-----------------------------------------------------------------------------
1127 Chuck_VM_Shred
* Chuck_VM::spork( Chuck_VM_Shred
* shred
)
1129 // set the current time
1130 shred
->start
= m_shreduler
->now_system
;
1132 shred
->now
= shred
->wake_time
= m_shreduler
->now_system
;
1134 shred
->xid
= next_id();
1136 shred
->vm_ref
= this;
1139 // add it to the parent
1141 shred
->parent
->children
[shred
->xid
] = shred
;
1143 m_shreduler
->shredule( shred
);
1153 //-----------------------------------------------------------------------------
1156 //-----------------------------------------------------------------------------
1157 t_CKBOOL
Chuck_VM::free( Chuck_VM_Shred
* shred
, t_CKBOOL cascade
, t_CKBOOL dec
)
1162 EM_log( CK_LOG_FINER
, "freeing shred (id==%d | ptr==%p)", shred
->xid
,
1165 // abort on the double free
1166 // TODO: can a shred be dumped, then resporked? from code?
1167 if( shred
->is_dumped
) return FALSE
;
1170 shred
->is_done
= TRUE
;
1172 // free the children
1173 t_CKINT size
= shred
->children
.size();
1176 vector
<Chuck_VM_Shred
*> list
; list
.resize( size
);
1177 map
<t_CKUINT
, Chuck_VM_Shred
*>::iterator iter
; t_CKINT i
= 0;
1178 for( iter
= shred
->children
.begin(); iter
!= shred
->children
.end(); iter
++ )
1179 list
[i
++] = (*iter
).second
;
1180 for( i
= 0; i
< size
; i
++ )
1181 this->free( list
[i
], cascade
);
1184 // make sure it's done
1185 assert( shred
->children
.size() == 0 );
1189 shred
->parent
->children
.erase( shred
->xid
);
1191 // track remove shred
1192 CK_TRACK( Chuck_Stats::instance()->remove_shred( shred
) );
1195 m_shreduler
->remove( shred
);
1196 // TODO: remove shred from event, with synchronization (still necessary with dump?)
1197 // if( shred->event ) shred->event->remove( shred );
1198 // OLD: shred->release();
1199 this->dump( shred
);
1201 if( dec
) m_num_shreds
--;
1202 if( !m_num_shreds
) m_shred_id
= 0;
1210 //-----------------------------------------------------------------------------
1211 // name: abort_current_shred()
1213 //-----------------------------------------------------------------------------
1214 t_CKBOOL
Chuck_VM::abort_current_shred( )
1217 Chuck_VM_Shred
* shred
= m_shreduler
->m_current_shred
;
1223 EM_log( CK_LOG_SEVERE
, "trying to abort current shred (id: %d)", shred
->xid
);
1225 shred
->is_abort
= TRUE
;
1230 EM_log( CK_LOG_SEVERE
, "cannot abort shred: nothing currently running!" );
1233 return shred
!= NULL
;
1239 //-----------------------------------------------------------------------------
1242 //-----------------------------------------------------------------------------
1243 void Chuck_VM::dump( Chuck_VM_Shred
* shred
)
1246 EM_log( CK_LOG_FINER
, "dumping shred (id==%d | ptr==%p)", shred
->xid
,
1249 m_shred_dump
.push_back( shred
);
1251 shred
->is_running
= FALSE
;
1252 shred
->is_done
= TRUE
;
1253 shred
->is_dumped
= TRUE
;
1257 m_num_dumped_shreds
++;
1263 //-----------------------------------------------------------------------------
1264 // name: release_dump()
1266 //-----------------------------------------------------------------------------
1267 void Chuck_VM::release_dump( )
1270 EM_log( CK_LOG_FINER
, "releasing dumped shreds..." );
1272 // iterate through dump
1273 for( t_CKUINT i
= 0; i
< m_shred_dump
.size(); i
++ )
1274 SAFE_RELEASE( m_shred_dump
[i
] );
1277 m_shred_dump
.clear();
1279 m_num_dumped_shreds
= 0;
1285 //-----------------------------------------------------------------------------
1286 // name: Chuck_VM_Stack()
1288 //-----------------------------------------------------------------------------
1289 Chuck_VM_Stack::Chuck_VM_Stack()
1291 stack
= sp
= sp_max
= NULL
;
1299 //-----------------------------------------------------------------------------
1300 // name: ~Chuck_VM_Stack()
1302 //-----------------------------------------------------------------------------
1303 Chuck_VM_Stack::~Chuck_VM_Stack()
1311 //-----------------------------------------------------------------------------
1312 // name: Chuck_VM_Code()
1314 //-----------------------------------------------------------------------------
1315 Chuck_VM_Code::Chuck_VM_Code()
1322 native_func_type
= NATIVE_UNKNOWN
;
1328 //-----------------------------------------------------------------------------
1329 // name: ~Chuck_VM_Code()
1331 //-----------------------------------------------------------------------------
1332 Chuck_VM_Code::~Chuck_VM_Code()
1334 // free instructions
1338 for( t_CKUINT i
= 0; i
< num_instr
; i
++ )
1342 SAFE_DELETE_ARRAY( instr
);
1351 // offset in bytes at the beginning of a stack for initializing data
1352 #define VM_STACK_OFFSET 16
1353 // 1/factor of stack is left blank, to give room to detect overflow
1354 #define VM_STACK_PADDING_FACTOR 16
1355 //-----------------------------------------------------------------------------
1356 // name: initialize()
1358 //-----------------------------------------------------------------------------
1359 t_CKBOOL
Chuck_VM_Stack::initialize( t_CKUINT size
)
1364 // make room for header
1365 size
+= VM_STACK_OFFSET
;
1367 stack
= new t_CKBYTE
[size
];
1368 if( !stack
) goto out_of_memory
;
1371 memset( stack
, 0, size
);
1373 // advance stack after the header
1374 stack
+= VM_STACK_OFFSET
;
1377 // upper limit (padding factor)
1378 sp_max
= sp
+ size
- (size
/ VM_STACK_PADDING_FACTOR
);
1380 // set flag and return
1381 return m_is_init
= TRUE
;
1385 // we have a problem
1387 "[chuck](VM): OutOfMemory: while allocating stack '%s'\n" );
1396 //-----------------------------------------------------------------------------
1399 //-----------------------------------------------------------------------------
1400 t_CKBOOL
Chuck_VM_Stack::shutdown()
1406 stack
-= VM_STACK_OFFSET
;
1407 SAFE_DELETE_ARRAY( stack
);
1410 // set the flag to false
1419 //-----------------------------------------------------------------------------
1420 // name: Chuck_VM_Shred()
1422 //-----------------------------------------------------------------------------
1423 Chuck_VM_Shred::Chuck_VM_Shred()
1425 mem
= new Chuck_VM_Stack
;
1426 reg
= new Chuck_VM_Stack
;
1431 // obj_array = NULL;
1432 // obj_array_size = 0;
1439 CK_TRACK( stat
= NULL
);
1445 //-----------------------------------------------------------------------------
1446 // name: ~Chuck_VM_Shred()
1448 //-----------------------------------------------------------------------------
1449 Chuck_VM_Shred::~Chuck_VM_Shred()
1457 //-----------------------------------------------------------------------------
1458 // name: initialize()
1460 //-----------------------------------------------------------------------------
1461 t_CKBOOL
Chuck_VM_Shred::initialize( Chuck_VM_Code
* c
,
1462 t_CKUINT mem_stack_size
,
1463 t_CKUINT reg_stack_size
)
1465 // allocate mem and reg
1466 if( !mem
->initialize( mem_stack_size
) ) return FALSE
;
1467 if( !reg
->initialize( reg_stack_size
) ) return FALSE
;
1473 code_orig
= code
= c
;
1475 code_orig
->add_ref();
1476 // shred in dump (all done)
1490 initialize_object( this, &t_shred
);
1498 //-----------------------------------------------------------------------------
1501 //-----------------------------------------------------------------------------
1502 t_CKBOOL
Chuck_VM_Shred::shutdown()
1504 // get iterator to our map
1505 map
<Chuck_UGen
*, Chuck_UGen
*>::iterator iter
= m_ugen_map
.begin();
1506 while( iter
!= m_ugen_map
.end() )
1508 (*iter
).first
->disconnect( TRUE
);
1517 // delete temp pointer space
1518 // SAFE_DELETE_ARRAY( obj_array );
1519 // obj_array_size = 0;
1521 // TODO: is this right?
1522 code_orig
->release();
1523 code_orig
= code
= NULL
;
1524 // what to do with next and prev?
1532 //-----------------------------------------------------------------------------
1535 //-----------------------------------------------------------------------------
1536 t_CKBOOL
Chuck_VM_Shred::add( Chuck_UGen
* ugen
)
1538 if( m_ugen_map
[ugen
] )
1541 m_ugen_map
[ugen
] = ugen
;
1548 //-----------------------------------------------------------------------------
1551 //-----------------------------------------------------------------------------
1552 t_CKBOOL
Chuck_VM_Shred::remove( Chuck_UGen
* ugen
)
1554 if( !m_ugen_map
[ugen
] )
1558 m_ugen_map
.erase( ugen
);
1565 //-----------------------------------------------------------------------------
1568 //-----------------------------------------------------------------------------
1569 t_CKBOOL
Chuck_VM_Shred::run( Chuck_VM
* vm
)
1572 instr
= code
->instr
;
1574 t_CKBOOL
* vm_running
= &vm
->m_running
;
1577 while( is_running
&& *vm_running
&& !is_abort
)
1579 // execute the instruction
1580 instr
[pc
]->execute( vm
, this );
1586 // track number of cycles
1587 CK_TRACK( this->stat
->cycles
++ );
1594 EM_log( CK_LOG_SYSTEM
, "aborting shred (id: %d)", this->xid
);
1599 // is the shred finished
1606 //-----------------------------------------------------------------------------
1607 // name: Chuck_VM_Shreduler()
1609 //-----------------------------------------------------------------------------
1610 Chuck_VM_Shreduler::Chuck_VM_Shreduler()
1616 m_current_shred
= NULL
;
1620 m_num_dac_channels
= 0;
1621 m_num_adc_channels
= 0;
1629 //-----------------------------------------------------------------------------
1630 // name: ~Chuck_VM_Shreduler()
1632 //-----------------------------------------------------------------------------
1633 Chuck_VM_Shreduler::~Chuck_VM_Shreduler()
1641 //-----------------------------------------------------------------------------
1642 // name: initialize()
1644 //-----------------------------------------------------------------------------
1645 t_CKBOOL
Chuck_VM_Shreduler::initialize()
1653 //-----------------------------------------------------------------------------
1656 //-----------------------------------------------------------------------------
1657 t_CKBOOL
Chuck_VM_Shreduler::shutdown()
1665 //-----------------------------------------------------------------------------
1666 // name: set_adaptive()
1668 //-----------------------------------------------------------------------------
1669 void Chuck_VM_Shreduler::set_adaptive( t_CKUINT max_block_size
)
1671 m_max_block_size
= max_block_size
> 1 ? max_block_size
: 0;
1672 m_adaptive
= m_max_block_size
> 1;
1673 m_samps_until_next
= -1;
1679 //-----------------------------------------------------------------------------
1680 // name: add_blocked()
1681 // desc: add shred to the shreduler's blocked list
1682 //-----------------------------------------------------------------------------
1683 t_CKBOOL
Chuck_VM_Shreduler::add_blocked( Chuck_VM_Shred
* shred
)
1685 // add shred to map, using pointer
1686 blocked
[shred
] = shred
;
1694 //-----------------------------------------------------------------------------
1695 // name: remove_blocked()
1696 // desc: remove shred from the shreduler's blocked list
1697 //-----------------------------------------------------------------------------
1698 t_CKBOOL
Chuck_VM_Shreduler::remove_blocked( Chuck_VM_Shred
* shred
)
1701 std::map
<Chuck_VM_Shred
*, Chuck_VM_Shred
*>::iterator iter
;
1702 iter
= blocked
.find( shred
);
1703 blocked
.erase( iter
);
1705 // remove from event
1706 if( shred
->event
!= NULL
) shred
->event
->remove( shred
);
1714 //-----------------------------------------------------------------------------
1717 //-----------------------------------------------------------------------------
1718 t_CKBOOL
Chuck_VM_Shreduler::shredule( Chuck_VM_Shred
* shred
)
1720 return this->shredule( shred
, now_system
);
1726 //-----------------------------------------------------------------------------
1729 //-----------------------------------------------------------------------------
1730 t_CKBOOL
Chuck_VM_Shreduler::shredule( Chuck_VM_Shred
* shred
,
1731 t_CKTIME wake_time
)
1734 if( shred
->prev
|| shred
->next
)
1736 // something is really wrong here - no shred can be
1737 // shreduled more than once
1738 EM_error3( "[chuck](VM): internal sanity check failed in shredule()" );
1739 EM_error3( "[chuck](VM): (shred shreduled while shreduled)" );
1745 if( wake_time
< (this->now_system
- .5) )
1747 // trying to enqueue on a time that is less than now
1748 EM_error3( "[chuck](VM): internal sanity check failed in shredule()" );
1749 EM_error3( "[chuck](VM): (wake time is past) - %f : %f", wake_time
, this->now_system
);
1754 shred
->wake_time
= wake_time
;
1761 // pointers to the shred queue
1762 Chuck_VM_Shred
* curr
= shred_list
;
1763 Chuck_VM_Shred
* prev
= NULL
;
1767 // found the place to insert
1768 if( curr
->wake_time
> wake_time
)
1777 shred
->next
= shred_list
;
1778 if( shred_list
) shred_list
->prev
= shred
;
1783 // insert the shred in sorted order
1784 shred
->next
= prev
->next
;
1786 if( prev
->next
) prev
->next
->prev
= shred
;
1791 t_CKTIME diff
= shred_list
->wake_time
- this->now_system
;
1792 if( diff
< 0 ) diff
= 0;
1793 // if( diff < m_samps_until_next )
1794 m_samps_until_next
= diff
;
1802 //-----------------------------------------------------------------------------
1803 // name: advance_v()
1805 //-----------------------------------------------------------------------------
1806 void Chuck_VM_Shreduler::advance_v( t_CKINT
& numLeft
)
1808 t_CKINT i
, j
, numFrames
;
1809 SAMPLE frame
[128], gain
[128], sum
;
1810 BBQ
* audio
= this->bbq
;
1812 // compute number of frames to compute; update
1813 numFrames
= ck_min( m_max_block_size
, numLeft
);
1814 if( this->m_samps_until_next
>= 0 )
1816 numFrames
= (t_CKINT
)(ck_min( numFrames
, this->m_samps_until_next
));
1817 if( numFrames
== 0 ) numFrames
= 1;
1818 this->m_samps_until_next
-= numFrames
;
1820 numLeft
-= numFrames
;
1822 // advance system 'now'
1823 this->now_system
+= numFrames
;
1828 for( j
= 0; j
< m_num_adc_channels
; j
++ )
1831 m_adc
->m_multi_chan
[j
]->m_time
= this->now_system
;
1833 gain
[j
] = m_adc
->m_multi_chan
[j
]->m_gain
;
1837 for( i
= 0; i
< numFrames
; i
++ )
1840 audio
->digi_in()->tick_in( frame
, m_num_adc_channels
);
1843 // loop over channels
1844 for( j
= 0; j
< m_num_adc_channels
; j
++ )
1846 m_adc
->m_multi_chan
[j
]->m_current_v
[i
] = frame
[j
] * gain
[j
] * m_adc
->m_gain
;
1847 sum
+= m_adc
->m_multi_chan
[j
]->m_current_v
[i
];
1849 m_adc
->m_current_v
[i
] = sum
/ m_num_adc_channels
;
1852 for( j
= 0; j
< m_num_adc_channels
; j
++ )
1855 m_adc
->m_multi_chan
[j
]->m_last
= m_adc
->m_multi_chan
[j
]->m_current_v
[numFrames
-1];
1858 m_adc
->m_last
= m_adc
->m_current_v
[numFrames
-1];
1860 m_adc
->m_time
= this->now_system
;
1864 m_dac
->system_tick_v( this->now_system
, numFrames
);
1867 m_bunghole
->system_tick_v( this->now_system
, numFrames
);
1870 for( i
= 0; i
< numFrames
; i
++ )
1872 for( j
= 0; j
< m_num_dac_channels
; j
++ )
1873 frame
[j
] = m_dac
->m_multi_chan
[j
]->m_current_v
[i
];
1876 audio
->digi_out()->tick_out( frame
, m_num_dac_channels
);
1883 //-----------------------------------------------------------------------------
1886 //-----------------------------------------------------------------------------
1887 void Chuck_VM_Shreduler::advance2( )
1889 // advance system 'now'
1890 this->now_system
+= 1;
1894 BBQ
* audio
= this->bbq
;
1899 audio
->digi_in()->tick_in( &l
, &r
);
1900 m_adc
->m_multi_chan
[0]->m_current
= l
* m_adc
->m_multi_chan
[0]->m_gain
;
1901 m_adc
->m_multi_chan
[1]->m_current
= r
* m_adc
->m_multi_chan
[1]->m_gain
;
1902 m_adc
->m_current
= .5f
* ( l
+ r
);
1904 m_adc
->m_multi_chan
[0]->m_time
= this->now_system
;
1905 m_adc
->m_multi_chan
[1]->m_time
= this->now_system
;
1906 m_adc
->m_time
= this->now_system
;
1910 m_dac
->system_tick( this->now_system
);
1911 l
= m_dac
->m_multi_chan
[0]->m_current
;
1912 r
= m_dac
->m_multi_chan
[1]->m_current
;
1914 // l *= .5f; r *= .5f;
1917 m_bunghole
->system_tick( this->now_system
);
1920 audio
->digi_out()->tick_out( l
, r
);
1926 //-----------------------------------------------------------------------------
1929 //-----------------------------------------------------------------------------
1930 void Chuck_VM_Shreduler::advance( )
1932 // advance system 'now'
1933 this->now_system
+= 1;
1938 BBQ
* audio
= this->bbq
;
1944 audio
->digi_in()->tick_in( frame
, m_num_adc_channels
);
1946 // loop over channels
1947 for( i
= 0; i
< m_num_adc_channels
; i
++ )
1949 m_adc
->m_multi_chan
[i
]->m_current
= frame
[i
] * m_adc
->m_multi_chan
[i
]->m_gain
* m_adc
->m_gain
;
1950 m_adc
->m_multi_chan
[i
]->m_last
= m_adc
->m_multi_chan
[i
]->m_current
;
1951 m_adc
->m_multi_chan
[i
]->m_time
= this->now_system
;
1952 sum
+= m_adc
->m_multi_chan
[i
]->m_current
;
1954 m_adc
->m_last
= m_adc
->m_current
= sum
/ m_num_adc_channels
;
1955 m_adc
->m_time
= this->now_system
;
1959 m_dac
->system_tick( this->now_system
);
1960 for( i
= 0; i
< m_num_dac_channels
; i
++ )
1961 frame
[i
] = m_dac
->m_multi_chan
[i
]->m_current
; // * .5f;
1964 m_bunghole
->system_tick( this->now_system
);
1967 audio
->digi_out()->tick_out( frame
, m_num_dac_channels
);
1973 //-----------------------------------------------------------------------------
1976 //-----------------------------------------------------------------------------
1977 Chuck_VM_Shred
* Chuck_VM_Shreduler::get( )
1979 Chuck_VM_Shred
* shred
= shred_list
;
1984 m_samps_until_next
= -1;
1988 // TODO: should this be <=?
1989 if( shred
->wake_time
<= ( this->now_system
+ .5 ) )
1991 // if( shred->wake_time < this->now_system )
1994 shred_list
= shred
->next
;
2000 shred_list
->prev
= NULL
;
2001 m_samps_until_next
= shred_list
->wake_time
- this->now_system
;
2002 if( m_samps_until_next
< 0 ) m_samps_until_next
= 0;
2014 //-----------------------------------------------------------------------------
2017 //-----------------------------------------------------------------------------
2018 t_CKUINT
Chuck_VM_Shreduler::highest( )
2020 Chuck_VM_Shred
* shred
= shred_list
;
2025 if( shred
->xid
> n
) n
= shred
->xid
;
2026 shred
= shred
->next
;
2029 std::map
<Chuck_VM_Shred
*, Chuck_VM_Shred
*>::iterator iter
;
2030 for( iter
= blocked
.begin(); iter
!= blocked
.end(); iter
++ )
2032 shred
= (*iter
).second
;
2033 if( shred
->xid
> n
) n
= shred
->xid
;
2042 //-----------------------------------------------------------------------------
2045 //-----------------------------------------------------------------------------
2046 t_CKBOOL
Chuck_VM_Shreduler::replace( Chuck_VM_Shred
* out
, Chuck_VM_Shred
* in
)
2057 out
->prev
->next
= in
;
2060 out
->next
->prev
= in
;
2062 in
->next
= out
->next
;
2063 in
->prev
= out
->prev
;
2065 out
->next
= out
->prev
= NULL
;
2067 in
->wake_time
= out
->wake_time
;
2068 in
->start
= in
->wake_time
;
2076 //-----------------------------------------------------------------------------
2079 //-----------------------------------------------------------------------------
2080 t_CKBOOL
Chuck_VM_Shreduler::remove( Chuck_VM_Shred
* out
)
2082 if( !out
) return FALSE
;
2085 if( out
->event
!= NULL
)
2087 return remove_blocked( out
);
2091 if( !out
->prev
&& !out
->next
&& out
!= shred_list
)
2095 shred_list
= out
->next
;
2097 out
->prev
->next
= out
->next
;
2100 out
->next
->prev
= out
->prev
;
2102 out
->next
= out
->prev
= NULL
;
2110 //-----------------------------------------------------------------------------
2113 //-----------------------------------------------------------------------------
2114 Chuck_VM_Shred
* Chuck_VM_Shreduler::lookup( t_CKUINT xid
)
2116 Chuck_VM_Shred
* shred
= shred_list
;
2119 if( m_current_shred
!= NULL
&& m_current_shred
->xid
== xid
)
2120 return m_current_shred
;
2122 // look for in shreduled list
2125 if( shred
->xid
== xid
)
2128 shred
= shred
->next
;
2132 std::map
<Chuck_VM_Shred
*, Chuck_VM_Shred
*>::iterator iter
;
2133 for( iter
= blocked
.begin(); iter
!= blocked
.end(); iter
++ )
2135 shred
= (*iter
).second
;
2136 if( shred
->xid
== xid
)
2146 //-----------------------------------------------------------------------------
2149 //-----------------------------------------------------------------------------
2152 bool operator() ( const Chuck_VM_Shred
* lhs
, const Chuck_VM_Shred
* rhs
)
2153 { return lhs
->xid
< rhs
->xid
; }
2159 //-----------------------------------------------------------------------------
2162 //-----------------------------------------------------------------------------
2163 void Chuck_VM_Shreduler::status( Chuck_VM_Status
* status
)
2165 Chuck_VM_Shred
* shred
= shred_list
;
2166 Chuck_VM_Shred
* temp
= NULL
;
2168 t_CKUINT srate
= Digitalio::sampling_rate();
2169 t_CKUINT s
= (t_CKUINT
)now_system
;
2170 t_CKUINT h
= s
/(srate
*3600);
2171 s
= s
- (h
*(srate
*3600));
2172 t_CKUINT m
= s
/ (srate
*60);
2173 s
= s
- (m
*(srate
*60));
2174 t_CKUINT sec
= s
/ srate
;
2175 s
= s
- (sec
*(srate
));
2176 // float millisecond = s / (float)(srate) * 1000.0f;
2178 status
->srate
= srate
;
2179 status
->now_system
= now_system
;
2180 status
->t_second
= sec
;
2181 status
->t_minute
= m
;
2184 // get list of shreds
2185 vector
<Chuck_VM_Shred
*> list
;
2188 list
.push_back( shred
);
2189 shred
= shred
->next
;
2193 std::map
<Chuck_VM_Shred
*, Chuck_VM_Shred
*>::iterator iter
;
2194 for( iter
= blocked
.begin(); iter
!= blocked
.end(); iter
++ )
2196 shred
= (*iter
).second
;
2197 list
.push_back( shred
);
2200 // get current shred
2201 if( temp
= m_current_shred
)
2202 list
.push_back( temp
);
2206 std::sort( list
.begin(), list
.end(), byid
);
2210 for( t_CKUINT i
= 0; i
< list
.size(); i
++ )
2213 status
->list
.push_back( new Chuck_VM_Shred_Status(
2214 shred
->xid
, shred
->name
, shred
->start
, shred
->event
!= NULL
) );
2221 //-----------------------------------------------------------------------------
2224 //-----------------------------------------------------------------------------
2225 void Chuck_VM_Shreduler::status( )
2227 Chuck_VM_Shred_Status
* shred
= NULL
;
2229 this->status( &m_status
);
2230 t_CKUINT h
= m_status
.t_hour
;
2231 t_CKUINT m
= m_status
.t_minute
;
2232 t_CKUINT sec
= m_status
.t_second
;
2233 fprintf( stdout
, "[chuck](VM): status (now == %ldh%ldm%lds, %.1f samps) ...\n",
2234 h
, m
, sec
, m_status
.now_system
);
2237 for( t_CKUINT i
= 0; i
< m_status
.list
.size(); i
++ )
2239 shred
= m_status
.list
[i
];
2241 " [shred id]: %ld [source]: %s [spork time]: %.2fs ago%s\n",
2242 shred
->xid
, mini( shred
->name
.c_str() ),
2243 (m_status
.now_system
- shred
->start
) / m_status
.srate
,
2244 shred
->has_event
? " (blocked)" : "" );
2251 //-----------------------------------------------------------------------------
2252 // name: Chuck_VM_Status()
2254 //-----------------------------------------------------------------------------
2255 Chuck_VM_Status::Chuck_VM_Status()
2259 t_second
= t_minute
= t_hour
= 0;
2265 //-----------------------------------------------------------------------------
2266 // name: ~Chuck_VM_Status()
2268 //-----------------------------------------------------------------------------
2269 Chuck_VM_Status::~Chuck_VM_Status()
2277 //-----------------------------------------------------------------------------
2280 //-----------------------------------------------------------------------------
2281 void Chuck_VM_Status::clear()
2283 for( t_CKUINT i
= 0; i
< list
.size(); i
++ )
2285 SAFE_DELETE( list
[i
] );