forked from len0rd/rockbox
Cut the files in half and it might work better (note to self: check your tree is really clean before patching)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21070 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
4f2dfcc01b
commit
526b5580da
192 changed files with 20 additions and 69133 deletions
|
@ -579,584 +579,4 @@ void sys_exit(void)
|
|||
{
|
||||
sys_quit = 1;
|
||||
}
|
||||
/* Copyright (c) 1997-1999 Miller Puckette.
|
||||
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
|
||||
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
|
||||
|
||||
/* scheduling stuff */
|
||||
|
||||
#include "m_pd.h"
|
||||
#include "m_imp.h"
|
||||
#include "s_stuff.h"
|
||||
|
||||
/* LATER consider making this variable. It's now the LCM of all sample
|
||||
rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
|
||||
#define TIMEUNITPERSEC (32.*441000.)
|
||||
|
||||
|
||||
/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */
|
||||
#define THREAD_LOCKING
|
||||
#include "pthread.h"
|
||||
|
||||
|
||||
static int sys_quit;
|
||||
static t_time sys_time;
|
||||
static t_time sys_time_per_msec = TIMEUNITPERSEC / 1000.;
|
||||
|
||||
int sys_schedblocksize = DEFDACBLKSIZE;
|
||||
int sys_usecsincelastsleep(void);
|
||||
int sys_sleepgrain;
|
||||
|
||||
typedef void (*t_clockmethod)(void *client);
|
||||
|
||||
struct _clock
|
||||
{
|
||||
t_time c_settime;
|
||||
void *c_owner;
|
||||
t_clockmethod c_fn;
|
||||
struct _clock *c_next;
|
||||
};
|
||||
|
||||
t_clock *clock_setlist;
|
||||
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
t_clock *clock_new(void *owner, t_method fn)
|
||||
{
|
||||
t_clock *x = (t_clock *)getbytes(sizeof *x);
|
||||
x->c_settime = -1;
|
||||
x->c_owner = owner;
|
||||
x->c_fn = (t_clockmethod)fn;
|
||||
x->c_next = 0;
|
||||
return (x);
|
||||
}
|
||||
|
||||
void clock_unset(t_clock *x)
|
||||
{
|
||||
if (x->c_settime >= 0)
|
||||
{
|
||||
if (x == clock_setlist) clock_setlist = x->c_next;
|
||||
else
|
||||
{
|
||||
t_clock *x2 = clock_setlist;
|
||||
while (x2->c_next != x) x2 = x2->c_next;
|
||||
x2->c_next = x->c_next;
|
||||
}
|
||||
x->c_settime = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the clock to call back at an absolute system time */
|
||||
void clock_set(t_clock *x, t_time setticks)
|
||||
{
|
||||
if (setticks < sys_time) setticks = sys_time;
|
||||
clock_unset(x);
|
||||
x->c_settime = setticks;
|
||||
if (clock_setlist && clock_setlist->c_settime <= setticks)
|
||||
{
|
||||
t_clock *cbefore, *cafter;
|
||||
for (cbefore = clock_setlist, cafter = clock_setlist->c_next;
|
||||
cbefore; cbefore = cafter, cafter = cbefore->c_next)
|
||||
{
|
||||
if (!cafter || cafter->c_settime > setticks)
|
||||
{
|
||||
cbefore->c_next = x;
|
||||
x->c_next = cafter;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else x->c_next = clock_setlist, clock_setlist = x;
|
||||
}
|
||||
|
||||
/* set the clock to call back after a delay in msec */
|
||||
void clock_delay(t_clock *x, t_time delaytime)
|
||||
{
|
||||
clock_set(x, sys_time + sys_time_per_msec * delaytime);
|
||||
}
|
||||
|
||||
/* get current logical time. We don't specify what units this is in;
|
||||
use clock_gettimesince() to measure intervals from time of this call.
|
||||
This was previously, incorrectly named "clock_getsystime"; the old
|
||||
name is aliased to the new one in m_pd.h. */
|
||||
t_time clock_getlogicaltime( void)
|
||||
{
|
||||
return (sys_time);
|
||||
}
|
||||
/* OBSOLETE NAME */
|
||||
t_time clock_getsystime( void) { return (sys_time); }
|
||||
|
||||
/* elapsed time in milliseconds since the given system time */
|
||||
t_time clock_gettimesince(t_time prevsystime)
|
||||
{
|
||||
return ((sys_time - prevsystime)/sys_time_per_msec);
|
||||
}
|
||||
|
||||
/* what value the system clock will have after a delay */
|
||||
t_time clock_getsystimeafter(t_time delaytime)
|
||||
{
|
||||
return (sys_time + sys_time_per_msec * delaytime);
|
||||
}
|
||||
|
||||
void clock_free(t_clock *x)
|
||||
{
|
||||
clock_unset(x);
|
||||
freebytes(x, sizeof *x);
|
||||
}
|
||||
|
||||
|
||||
/* the following routines maintain a real-execution-time histogram of the
|
||||
various phases of real-time execution. */
|
||||
|
||||
static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
|
||||
#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
|
||||
#define NHIST 10
|
||||
static int sys_histogram[NHIST][NBIN];
|
||||
static t_time sys_histtime;
|
||||
static int sched_diddsp, sched_didpoll, sched_didnothing;
|
||||
|
||||
static void sys_clearhist( void)
|
||||
{
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < NHIST; i++)
|
||||
for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0;
|
||||
sys_histtime = sys_getrealtime();
|
||||
sched_diddsp = sched_didpoll = sched_didnothing = 0;
|
||||
}
|
||||
|
||||
void sys_printhist( void)
|
||||
{
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < NHIST; i++)
|
||||
{
|
||||
int doit = 0;
|
||||
for (j = 0; j < NBIN; j++) if (sys_histogram[i][j]) doit = 1;
|
||||
if (doit)
|
||||
{
|
||||
post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
|
||||
sys_histogram[i][0],
|
||||
sys_histogram[i][1],
|
||||
sys_histogram[i][2],
|
||||
sys_histogram[i][3],
|
||||
sys_histogram[i][4],
|
||||
sys_histogram[i][5],
|
||||
sys_histogram[i][6],
|
||||
sys_histogram[i][7]);
|
||||
}
|
||||
}
|
||||
post("dsp %d, pollgui %d, nothing %d",
|
||||
sched_diddsp, sched_didpoll, sched_didnothing);
|
||||
}
|
||||
|
||||
static int sys_histphase;
|
||||
|
||||
int sys_addhist(int phase)
|
||||
{
|
||||
#ifndef FIXEDPOINT
|
||||
int i, j, phasewas = sys_histphase;
|
||||
t_time newtime = sys_getrealtime();
|
||||
int msec = (newtime - sys_histtime) * 1000.;
|
||||
for (j = NBIN-1; j >= 0; j--)
|
||||
{
|
||||
if (msec >= sys_bin[j])
|
||||
{
|
||||
sys_histogram[phasewas][j]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sys_histtime = newtime;
|
||||
sys_histphase = phase;
|
||||
return (phasewas);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define NRESYNC 20
|
||||
|
||||
typedef struct _resync
|
||||
{
|
||||
int r_ntick;
|
||||
int r_error;
|
||||
} t_resync;
|
||||
|
||||
static int oss_resyncphase = 0;
|
||||
static int oss_nresync = 0;
|
||||
static t_resync oss_resync[NRESYNC];
|
||||
|
||||
|
||||
static char *(oss_errornames[]) = {
|
||||
"unknown",
|
||||
"ADC blocked",
|
||||
"DAC blocked",
|
||||
"A/D/A sync",
|
||||
"data late"
|
||||
};
|
||||
|
||||
void glob_audiostatus(void)
|
||||
{
|
||||
int dev, nresync, nresyncphase, i;
|
||||
nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync);
|
||||
nresyncphase = oss_resyncphase - 1;
|
||||
post("audio I/O error history:");
|
||||
post("seconds ago\terror type");
|
||||
for (i = 0; i < nresync; i++)
|
||||
{
|
||||
int errtype;
|
||||
if (nresyncphase < 0)
|
||||
nresyncphase += NRESYNC;
|
||||
errtype = oss_resync[nresyncphase].r_error;
|
||||
if (errtype < 0 || errtype > 4)
|
||||
errtype = 0;
|
||||
|
||||
post("%9.2f\t%s",
|
||||
(sched_diddsp - oss_resync[nresyncphase].r_ntick)
|
||||
* ((double)sys_schedblocksize) / sys_dacsr,
|
||||
oss_errornames[errtype]);
|
||||
nresyncphase--;
|
||||
}
|
||||
}
|
||||
|
||||
static int sched_diored;
|
||||
static int sched_dioredtime;
|
||||
static int sched_meterson;
|
||||
|
||||
void sys_log_error(int type)
|
||||
{
|
||||
oss_resync[oss_resyncphase].r_ntick = sched_diddsp;
|
||||
oss_resync[oss_resyncphase].r_error = type;
|
||||
oss_nresync++;
|
||||
if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
|
||||
if (type != ERR_NOTHING && !sched_diored &&
|
||||
(sched_diddsp >= sched_dioredtime))
|
||||
{
|
||||
sys_vgui("pdtk_pd_dio 1\n");
|
||||
sched_diored = 1;
|
||||
}
|
||||
sched_dioredtime =
|
||||
sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
|
||||
}
|
||||
|
||||
static int sched_lastinclip, sched_lastoutclip,
|
||||
sched_lastindb, sched_lastoutdb;
|
||||
|
||||
void glob_ping(t_pd *dummy);
|
||||
|
||||
static void sched_pollformeters( void)
|
||||
{
|
||||
int inclip, outclip, indb, outdb;
|
||||
static int sched_nextmeterpolltime, sched_nextpingtime;
|
||||
|
||||
/* if there's no GUI but we're running in "realtime", here is
|
||||
where we arrange to ping the watchdog every 2 seconds. */
|
||||
#ifdef __linux__
|
||||
if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
|
||||
{
|
||||
glob_ping(0);
|
||||
/* ping every 2 seconds */
|
||||
sched_nextpingtime = sched_diddsp +
|
||||
(2* sys_dacsr) /(int)sys_schedblocksize;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sched_diddsp - sched_nextmeterpolltime < 0)
|
||||
return;
|
||||
if (sched_diored && (sched_diddsp - sched_dioredtime > 0))
|
||||
{
|
||||
sys_vgui("pdtk_pd_dio 0\n");
|
||||
sched_diored = 0;
|
||||
}
|
||||
if (sched_meterson)
|
||||
{
|
||||
float inmax, outmax;
|
||||
sys_getmeters(&inmax, &outmax);
|
||||
indb = 0.5 + rmstodb(inmax);
|
||||
outdb = 0.5 + rmstodb(outmax);
|
||||
inclip = (inmax > 0.999);
|
||||
outclip = (outmax >= 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
indb = outdb = 0;
|
||||
inclip = outclip = 0;
|
||||
}
|
||||
if (inclip != sched_lastinclip || outclip != sched_lastoutclip
|
||||
|| indb != sched_lastindb || outdb != sched_lastoutdb)
|
||||
{
|
||||
sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
|
||||
sched_lastinclip = inclip;
|
||||
sched_lastoutclip = outclip;
|
||||
sched_lastindb = indb;
|
||||
sched_lastoutdb = outdb;
|
||||
}
|
||||
sched_nextmeterpolltime =
|
||||
sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
|
||||
}
|
||||
|
||||
void glob_meters(void *dummy, float f)
|
||||
{
|
||||
if (f == 0)
|
||||
sys_getmeters(0, 0);
|
||||
sched_meterson = (f != 0);
|
||||
sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb =
|
||||
-1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
|
||||
{
|
||||
if (argc) sys_clearhist();
|
||||
else sys_printhist();
|
||||
}
|
||||
#endif
|
||||
|
||||
void dsp_tick(void);
|
||||
|
||||
static int sched_usedacs = 1;
|
||||
static t_time sched_referencerealtime, sched_referencelogicaltime;
|
||||
static t_time sys_time_per_dsp_tick;
|
||||
|
||||
void sched_set_using_dacs(int flag)
|
||||
{
|
||||
sched_usedacs = flag;
|
||||
if (!flag)
|
||||
{
|
||||
sched_referencerealtime = sys_getrealtime();
|
||||
sched_referencelogicaltime = clock_getlogicaltime();
|
||||
post("schedsetuding");
|
||||
}
|
||||
sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
|
||||
((double)sys_schedblocksize) / sys_dacsr;
|
||||
}
|
||||
|
||||
/* take the scheduler forward one DSP tick, also handling clock timeouts */
|
||||
static void sched_tick(t_time next_sys_time)
|
||||
{
|
||||
int countdown = 5000;
|
||||
while (clock_setlist && clock_setlist->c_settime < next_sys_time)
|
||||
{
|
||||
t_clock *c = clock_setlist;
|
||||
sys_time = c->c_settime;
|
||||
clock_unset(clock_setlist);
|
||||
outlet_setstacklim();
|
||||
(*c->c_fn)(c->c_owner);
|
||||
if (!countdown--)
|
||||
{
|
||||
countdown = 5000;
|
||||
sys_pollgui();
|
||||
}
|
||||
if (sys_quit)
|
||||
return;
|
||||
}
|
||||
sys_time = next_sys_time;
|
||||
dsp_tick();
|
||||
sched_diddsp++;
|
||||
}
|
||||
|
||||
/*
|
||||
Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
|
||||
"ticks" deterministically, and polls for input from MIDI and the GUI. If
|
||||
we're left idle we also poll for graphics updates; but these are considered
|
||||
lower priority than the rest.
|
||||
|
||||
The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
|
||||
call. This call returns true if samples were transferred; false means that
|
||||
the audio I/O system is still busy with previous transfers.
|
||||
*/
|
||||
|
||||
void sys_pollmidiqueue( void);
|
||||
void sys_initmidiqueue( void);
|
||||
|
||||
int m_scheduler_pda( void)
|
||||
{
|
||||
int idlecount = 0;
|
||||
sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
|
||||
((double)sys_schedblocksize) / sys_dacsr;
|
||||
|
||||
|
||||
sys_clearhist();
|
||||
if (sys_sleepgrain < 1000)
|
||||
sys_sleepgrain = sys_schedadvance/4;
|
||||
if (sys_sleepgrain < 100)
|
||||
sys_sleepgrain = 100;
|
||||
else if (sys_sleepgrain > 5000)
|
||||
sys_sleepgrain = 5000;
|
||||
sys_initmidiqueue();
|
||||
while (!sys_quit)
|
||||
{
|
||||
int didsomething = 0;
|
||||
int timeforward;
|
||||
|
||||
sys_addhist(0);
|
||||
waitfortick:
|
||||
if (sched_usedacs)
|
||||
{
|
||||
timeforward = sys_send_dacs();
|
||||
sys_pollgui();
|
||||
}
|
||||
else {
|
||||
if ((sys_getrealtime() - sched_referencerealtime)
|
||||
> (t_time)clock_gettimesince(sched_referencelogicaltime)*1000)
|
||||
timeforward = SENDDACS_YES;
|
||||
else timeforward = SENDDACS_NO;
|
||||
if (timeforward == SENDDACS_YES)
|
||||
sys_microsleep(sys_sleepgrain);
|
||||
}
|
||||
if (timeforward != SENDDACS_NO) {
|
||||
sched_tick(sys_time + sys_time_per_dsp_tick);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int m_scheduler( void)
|
||||
{
|
||||
int idlecount = 0;
|
||||
sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
|
||||
((double)sys_schedblocksize) / sys_dacsr;
|
||||
|
||||
#ifdef THREAD_LOCKING
|
||||
/* T.Grill - lock mutex */
|
||||
sys_lock();
|
||||
#endif
|
||||
|
||||
sys_clearhist();
|
||||
if (sys_sleepgrain < 1000)
|
||||
sys_sleepgrain = sys_schedadvance/4;
|
||||
if (sys_sleepgrain < 100)
|
||||
sys_sleepgrain = 100;
|
||||
else if (sys_sleepgrain > 5000)
|
||||
sys_sleepgrain = 5000;
|
||||
sys_initmidiqueue();
|
||||
while (!sys_quit)
|
||||
{
|
||||
int didsomething = 0;
|
||||
int timeforward;
|
||||
|
||||
sys_addhist(0);
|
||||
waitfortick:
|
||||
if (sched_usedacs)
|
||||
{
|
||||
timeforward = sys_send_dacs();
|
||||
|
||||
/* if dacs remain "idle" for 1 sec, they're hung up. */
|
||||
if (timeforward != 0)
|
||||
idlecount = 0;
|
||||
else
|
||||
{
|
||||
idlecount++;
|
||||
if (!(idlecount & 31))
|
||||
{
|
||||
static t_time 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
|
||||
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 */
|
||||
sys_unlock();
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* ------------ thread locking ------------------- */
|
||||
/* added by Thomas Grill */
|
||||
|
||||
#ifdef THREAD_LOCKING
|
||||
static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void sys_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&sys_mutex);
|
||||
}
|
||||
|
||||
void sys_unlock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&sys_mutex);
|
||||
}
|
||||
|
||||
int sys_trylock(void)
|
||||
{
|
||||
return pthread_mutex_trylock(&sys_mutex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void sys_lock(void) {}
|
||||
void sys_unlock(void) {}
|
||||
int sys_trylock(void) {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* ------------ soft quit ------------------- */
|
||||
/* added by Thomas Grill -
|
||||
just set the quit flag for the scheduler loop
|
||||
this is useful for applications using the PD shared library to signal the scheduler to terminate
|
||||
*/
|
||||
|
||||
void sys_exit(void)
|
||||
{
|
||||
sys_quit = 1;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue