Update of /cvsroot/pure-data/pd/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24481
Modified Files: Tag: devel_0_38 m_sched.c Log Message: callback-based scheduler and generalized idle callbacks
Index: m_sched.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/m_sched.c,v retrieving revision 1.5.4.3 retrieving revision 1.5.4.4 diff -C2 -d -r1.5.4.3 -r1.5.4.4 *** m_sched.c 11 Nov 2004 22:30:41 -0000 1.5.4.3 --- m_sched.c 23 Nov 2004 23:07:40 -0000 1.5.4.4 *************** *** 23,26 **** --- 23,33 ---- static double sys_time_per_msec = TIMEUNITPERSEC / 1000.;
+ /* tb: { */ + int sys_keepsched = 1; /* if 0: change scheduler mode */ + int sys_callbackscheduler = 0; /* if 1: change scheduler to callback based dsp */ + + static t_int run_idle_callbacks(); + /* tb: }*/ + int sys_usecsincelastsleep(void); int sys_sleepgrain; *************** *** 387,390 **** --- 394,400 ---- int (*sys_idlehook)(void);
+ + + int m_scheduler( void) { *************** *** 395,399 **** #ifdef THREAD_LOCKING /* T.Grill - lock mutex */ ! sys_lock(); #endif
--- 405,409 ---- #ifdef THREAD_LOCKING /* T.Grill - lock mutex */ ! sys_lock(); #endif
*************** *** 408,505 **** while (!sys_quit) { ! int didsomething = 0; ! int timeforward;
! sys_addhist(0); ! waitfortick: ! if (sched_usedacs) ! { #ifdef THREAD_LOCKING ! /* T.Grill - send_dacs may sleep -> ! unlock thread lock make that time available ! - could messaging do any harm while sys_send_dacs is running? ! */ ! sys_unlock(); #endif ! timeforward = sys_send_dacs(); #ifdef THREAD_LOCKING ! /* T.Grill - done */ ! sys_unlock(); #endif ! /* if dacs remain "idle" for 1 sec, they're hung up. */ ! if (timeforward != 0) ! idlecount = 0; ! else ! { ! idlecount++; ! if (!(idlecount & 31)) ! { ! static double idletime; ! /* on 32nd idle, start a clock watch; every ! 32 ensuing idles, check it */ ! if (idlecount == 32) ! idletime = sys_getrealtime(); ! else if (sys_getrealtime() - idletime > 1.) ! { ! post("audio I/O stuck... closing audio\n"); ! sys_close_audio(); ! sched_set_using_dacs(0); ! goto waitfortick; ! } ! } ! } ! } ! else ! { ! if (1000. * (sys_getrealtime() - sched_referencerealtime) ! > clock_gettimesince(sched_referencelogicaltime)) ! timeforward = SENDDACS_YES; ! else timeforward = SENDDACS_NO; ! } ! sys_setmiditimediff(0, 1e-6 * sys_schedadvance); ! sys_addhist(1); ! if (timeforward != SENDDACS_NO) ! sched_tick(sys_time + sys_time_per_dsp_tick); ! if (timeforward == SENDDACS_YES) ! didsomething = 1;
! sys_addhist(2); ! sys_pollmidiqueue(); ! if (sys_pollgui()) ! { ! if (!didsomething) ! sched_didpoll++; ! didsomething = 1; ! } ! sys_addhist(3); ! /* test for idle; if so, do graphics updates. */ ! if (!didsomething) ! { ! sched_pollformeters(); ! sys_reportidle();
#ifdef THREAD_LOCKING ! /* T.Grill - enter idle phase -> unlock thread lock */ ! sys_unlock(); #endif ! /* call externally installed idle function if any. */ ! if (!sys_idlehook || !sys_idlehook()) ! { ! /* if even that had nothing to do, sleep. */ ! if (timeforward != SENDDACS_SLEPT) { ! sys_microsleep(sys_sleepgrain); } - } #ifdef THREAD_LOCKING ! /* T.Grill - leave idle phase -> lock thread lock */ ! sys_lock(); #endif ! sys_addhist(5); ! sched_didnothing++;
! } ! }
#ifdef THREAD_LOCKING /* T.Grill - done */ --- 418,568 ---- while (!sys_quit) { ! if (!sys_callbackscheduler) ! while (sys_keepsched) ! { ! int didsomething = 0; ! int timeforward;
! sys_addhist(0); ! waitfortick: ! if (sched_usedacs) ! { #ifdef THREAD_LOCKING ! /* T.Grill - send_dacs may sleep -> ! unlock thread lock make that time available ! - could messaging do any harm while sys_send_dacs is running? ! */ ! sys_unlock(); #endif ! timeforward = sys_send_dacs(); #ifdef THREAD_LOCKING ! /* T.Grill - done */ ! sys_unlock(); #endif ! /* if dacs remain "idle" for 1 sec, they're hung up. */ ! if (timeforward != 0) ! idlecount = 0; ! else ! { ! idlecount++; ! if (!(idlecount & 31)) ! { ! static double idletime; ! /* on 32nd idle, start a clock watch; every ! 32 ensuing idles, check it */ ! if (idlecount == 32) ! idletime = sys_getrealtime(); ! else if (sys_getrealtime() - idletime > 1.) ! { ! post("audio I/O stuck... closing audio\n"); ! sys_close_audio(); ! sched_set_using_dacs(0); ! goto waitfortick; ! } ! } ! } ! } ! else ! { ! if (1000. * (sys_getrealtime() - sched_referencerealtime) ! > clock_gettimesince(sched_referencelogicaltime)) ! timeforward = SENDDACS_YES; ! else timeforward = SENDDACS_NO; ! } ! sys_setmiditimediff(0, 1e-6 * sys_schedadvance); ! sys_addhist(1); ! if (timeforward != SENDDACS_NO) ! sched_tick(sys_time + sys_time_per_dsp_tick); ! if (timeforward == SENDDACS_YES) ! didsomething = 1;
! sys_addhist(2); ! sys_pollmidiqueue(); ! if (sys_pollgui()) ! { ! if (!didsomething) ! sched_didpoll++; ! didsomething = 1; ! } ! sys_addhist(3); ! /* test for idle; if so, do graphics updates. */ ! if (!didsomething) ! { ! sched_pollformeters(); ! sys_reportidle();
#ifdef THREAD_LOCKING ! /* T.Grill - enter idle phase -> unlock thread lock */ ! sys_unlock(); #endif ! /* tb: call idle callbacks */ ! if (run_idle_callbacks()) { ! /* if even that had nothing to do, sleep. */ ! if (timeforward != SENDDACS_SLEPT) ! { ! sys_microsleep(sys_sleepgrain); ! } } #ifdef THREAD_LOCKING ! /* T.Grill - leave idle phase -> lock thread lock */ ! sys_lock(); #endif ! sys_addhist(5); ! sched_didnothing++;
! } ! } ! else /* tb: scheduler for callback-based dsp scheduling */ ! while(sys_keepsched) ! { ! int didsomething = 0; ! int timeforward;
+ sys_addhist(0); + + sys_setmiditimediff(0, 1e-6 * sys_schedadvance); + sys_addhist(1); + + /* run this from the callback + */ + + sys_addhist(2); + sys_pollmidiqueue(); + if (sys_pollgui()) + { + if (!didsomething) + sched_didpoll++; + didsomething = 1; + } + sys_addhist(3); + + /* test for idle; if so, do graphics updates. */ + if (!didsomething) + { + sched_pollformeters(); + sys_reportidle(); + } + + #ifdef THREAD_LOCKING + sys_unlock(); + #endif + + /* sleep: the callback might run sched_tick during this time */ + sys_microsleep(sys_sleepgrain / 10); + + /* call externally installed idle function if any. */ + /* tb: is there a more elegant way to do this? */ + // sys_idlehook(); + + #ifdef THREAD_LOCKING + sys_lock(); + #endif + sys_addhist(5); + sched_didnothing++; + } + sys_keepsched = 1; + } + #ifdef THREAD_LOCKING /* T.Grill - done */ *************** *** 549,552 **** void sys_exit(void) { ! sys_quit = 1; } --- 612,691 ---- void sys_exit(void) { ! sys_keepsched = 0; ! sys_quit = 1; } + + + /* tb: place callbacks in scheduler + * { */ + + #if 1 + /* linked list of callbacks */ + typedef struct _sched_callback + { + void (*function) (t_int** argv); + t_int** argv; + t_int argc; + struct _sched_callback* next; + } t_sched_callback; + + /* this is not save ... possibly not atomic */ + static volatile t_sched_callback * cb_fifo_begin = NULL; + static volatile t_sched_callback * cb_fifo_end = NULL; + + void set_callback(void (*callback) (t_int** argv), t_int** argv, t_int argc) + { + t_sched_callback* new = (t_sched_callback*) getbytes + (sizeof(t_sched_callback)); + + new->function = callback; + new->argv = (t_int**) getbytes (argc * sizeof (t_int*)); + new->argc = argc; + new->next = NULL; + + if (cb_fifo_begin != NULL) + { + cb_fifo_end->next = new; + cb_fifo_end = new; + } + else + { + cb_fifo_begin = new; + cb_fifo_end = new; + } + + } + + + static t_int run_idle_callbacks() + { + if (cb_fifo_begin) + { + double stop = sys_getrealtime() + sys_sleepgrain; + + do + { + t_sched_callback* next = cb_fifo_begin->next; + cb_fifo_begin->function(cb_fifo_begin->argv); + + + freebytes (cb_fifo_begin->argv, cb_fifo_begin->argc); + freebytes ((void*)cb_fifo_begin, sizeof(t_sched_callback)); + + cb_fifo_begin = next; + } + while ( sys_getrealtime() > stop); + + return 0; /* don't sleep */ + } + return 1; /* sleep now */ + } + + + #else + + #error to be implemented + + #endif /* LOCK_FREE */ + + /* } tb */