In hope to answer some of the questions I presented on the pd-list the
other day, attached is the patch (diff -u against pd-extended svn
0.42.5) that converts miXed/cyclone/coll.c object into a threaded
version which in turn does not trigger xruns every time one tries to
open or save a file at runtime. This is particularly apparent when
opening/closing large files using low latency audio buffers. This
problem is also apparent in other similar objects (e.g. msgfile) and
should be ostensibly solvable using the same principle.
Additional lessons I learned from this exercise and am sharing them here
in hope others may benefit from them as well are as follows:
1) Spawning a secondary thread within an external (detached or not)
should in principle never result in an xrun, except in the coll object I
discovered that always the first thread creation did result in an xrun
which is why the code also does a bogus thread immediately following the
creation time using clock_delay. I am not sure whether this is
atom-CPU-specific or more widespread and/or whether this has to do with
the way PD is designed. Any thoughts are most appreciated here.
2) Triggering clock_delay from a separate thread works fine and should
be always used (rather than dealing with the outlet traffic directly) to
prevent out-of-sync gui operations which may result in gui
freezing/crashing.
Cheers!
Ico
--- coll.c.orig 2010-09-24 11:16:17.000000000 -0400
+++ coll.c 2010-09-25 11:23:27.000000000 -0400
@@ -9,6 +9,8 @@
#include "common/loud.h"
#include "hammer/file.h"
+#include <pthread.h>
+
/* LATER profile for the bottlenecks of insertion and sorting */
/* LATER make sure that ``reentrancy protection hack'' is really working... */
@@ -60,11 +62,53 @@
t_outlet *x_filebangout;
t_outlet *x_dumpbangout;
struct _coll *x_next;
+
+ //for thread-unsafe file i/o operations
+ //added by Ivica Ico Bukvic <[email protected]> 9-24-2010
+ //http://disis.music.vt.edu http://l2ork.music.vt.edu
+ t_clock *x_clock;
+ t_clock *x_init; /* for initializing first dummy thread */
+ pthread_t unsafer_t; /* read */
+ pthread_t unsafew_t; /* write */
+ pthread_attr_t unsafe_attr;
+
+ int busy; /* used as a simple one-way communication between the threads */
} t_coll;
+typedef struct _threadedFunctionParams
+{
+ t_coll *x;
+ t_collcommon *cc;
+ t_symbol *fn;
+ t_canvas *cv;
+} t_threadedFunctionParams;
+
static t_class *coll_class;
static t_class *collcommon_class;
+//pre-declare threaded functions
+static void *coll_threadedread(void *ptr);
+static void *coll_threadedwrite(void *ptr);
+
+void coll_tick(t_coll *x, int n)
+{
+ outlet_bang(x->x_filebangout);
+}
+
+void coll_dummy_init(t_coll *x)
+{
+ //first thread creation always trips an xrun (no idea why)
+ //so let's create a bogus one that will exit immediately since s is NULL
+ t_threadedFunctionParams rPars;
+ rPars.x = x;
+ rPars.cc = NULL;
+ rPars.fn = NULL;
+ rPars.cv = NULL;
+ pthread_create( &x->unsafer_t, &x->unsafe_attr, (void *) &coll_threadedread, (void *) &rPars);
+}
+
+
+
static t_collelem *collelem_new(int ac, t_atom *av, int *np, t_symbol *s)
{
t_collelem *ep = (t_collelem *)getbytes(sizeof(*ep));
@@ -201,6 +245,8 @@
}
}
+
+
/* atomic collcommon modifiers: clearall, remove, replace,
putbefore, putafter, swaplinks, swapkeys, changesymkey, renumber, sort */
@@ -582,6 +628,78 @@
return (collcommon_fromatoms(cc, binbuf_getnatom(bb), binbuf_getvec(bb)));
}
+static void *coll_threadedread(void *ptr)
+{
+ t_threadedFunctionParams *rPars = (t_threadedFunctionParams*)ptr;
+ t_coll *x = rPars->x;
+ t_collcommon *cc = rPars->cc;
+ t_symbol *fn = rPars->fn;
+ t_canvas *cv = rPars->cv;
+
+ if (!cc) /* safety */
+ return NULL;
+
+ t_binbuf *bb;
+ char buf[MAXPDSTRING];
+ if (!fn && !(fn = cc->c_filename)) /* !fn: 'readagain' */
+ return NULL;
+ /* FIXME use open_via_path() */
+ if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'read' w/o arg, 'readagain' */
+ canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ if (!cc->c_refs)
+ {
+ /* loading during object creation --
+ avoid binbuf_read()'s complaints, LATER rethink */
+ FILE *fp;
+ char fname[MAXPDSTRING];
+ sys_bashfilename(buf, fname);
+ if (!(fp = fopen(fname, "r")))
+ {
+ loud_warning(&coll_class, 0, "no coll file '%s'", fname);
+ return NULL;
+ }
+ fclose(fp);
+ }
+ bb = binbuf_new();
+ if (binbuf_read(bb, buf, "", 0))
+ loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+ else
+ {
+ int nlines = collcommon_frombinbuf(cc, bb);
+ if (nlines > 0)
+ {
+ t_coll *x;
+ /* LATER consider making this more robust */
+ for (x = cc->c_refs; x; x = x->x_next)
+
+ //do the call whenever the next gui update happens to ensure sync
+ //outlet_bang(x->x_filebangout);
+ clock_delay(x->x_clock, 0);
+
+ cc->c_lastcanvas = cv;
+ cc->c_filename = fn;
+ post("coll: finished reading %d lines from text file '%s'",
+ nlines, fn->s_name);
+ }
+ else if (nlines < 0)
+ loud_error(0, "coll: error in line %d of text file '%s'",
+ 1 - nlines, fn->s_name);
+ else
+ loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+ if (cc->c_refs)
+ collcommon_modified(cc, 1);
+ }
+ binbuf_free(bb);
+ //freebytes (ptr, sizeof (t_threadedFunctionParams));
+ x->busy = 0;
+ return NULL;
+}
+
static void collcommon_doread(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
{
t_binbuf *bb;
@@ -668,6 +786,45 @@
}
}
+static void *coll_threadedwrite(void *ptr)
+{
+ t_threadedFunctionParams *rPars = (t_threadedFunctionParams*)ptr;
+ t_coll *x = rPars->x;
+ t_collcommon *cc = rPars->cc;
+ t_symbol *fn = rPars->fn;
+ t_canvas *cv = rPars->cv;
+
+ if (!cc) /* safety */
+ return NULL;
+
+ t_binbuf *bb;
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ if (!fn && !(fn = cc->c_filename)) /* !fn: 'writeagain' */
+ return NULL;
+ if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'write' w/o arg, 'writeagain' */
+ canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ bb = binbuf_new();
+ collcommon_tobinbuf(cc, bb);
+ if (binbuf_write(bb, buf, "", 0))
+ loud_error(0, "coll: error writing text file '%s'", fn->s_name);
+ else
+ {
+ cc->c_lastcanvas = cv;
+ cc->c_filename = fn;
+ }
+ binbuf_free(bb);
+ //freebytes (ptr, sizeof (t_threadedFunctionParams));
+ x->busy = 0;
+ return NULL;
+}
+
static void collcommon_dowrite(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
{
t_binbuf *bb;
@@ -952,234 +1109,264 @@
static void coll_float(t_coll *x, t_float f)
{
- t_collcommon *cc = x->x_common;
- t_collelem *ep;
- int numkey;
- if (loud_checkint((t_pd *)x, f, &numkey, &s_float) &&
- (ep = collcommon_numkey(cc, numkey)))
- {
- coll_keyoutput(x, ep);
- if (!cc->c_selfmodified || (ep = collcommon_numkey(cc, numkey)))
- coll_dooutput(x, ep->e_size, ep->e_data);
- }
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, &s_float) &&
+ (ep = collcommon_numkey(cc, numkey)))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = collcommon_numkey(cc, numkey)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ }
}
static void coll_symbol(t_coll *x, t_symbol *s)
{
- t_collcommon *cc = x->x_common;
- t_collelem *ep;
- if (ep = collcommon_symkey(cc, s))
- {
- coll_keyoutput(x, ep);
- if (!cc->c_selfmodified || (ep = collcommon_symkey(cc, s)))
- coll_dooutput(x, ep->e_size, ep->e_data);
- }
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (ep = collcommon_symkey(cc, s))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = collcommon_symkey(cc, s)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ }
}
static void coll_list(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac >= 2 && av->a_type == A_FLOAT)
- coll_tokey(x, av, ac-1, av+1, 1, &s_list);
- else
- loud_messarg((t_pd *)x, &s_list);
+ if (!x->busy) {
+ if (ac >= 2 && av->a_type == A_FLOAT)
+ coll_tokey(x, av, ac-1, av+1, 1, &s_list);
+ else
+ loud_messarg((t_pd *)x, &s_list);
+ }
}
static void coll_anything(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- coll_symbol(x, s);
+ if (!x->busy)
+ coll_symbol(x, s);
}
static void coll_store(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac >= 2)
- coll_tokey(x, av, ac-1, av+1, 1, s);
- else
- loud_messarg((t_pd *)x, s);
+ if (!x->busy) {
+ if (ac >= 2)
+ coll_tokey(x, av, ac-1, av+1, 1, s);
+ else
+ loud_messarg((t_pd *)x, s);
+ }
}
static void coll_nstore(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac >= 3)
- {
- t_collcommon *cc = x->x_common;
- t_collelem *ep;
- int numkey;
- if (av->a_type == A_FLOAT && av[1].a_type == A_SYMBOL)
- {
- if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
- {
- if (ep = collcommon_symkey(cc, av[1].a_w.w_symbol))
- collcommon_remove(cc, ep);
- ep = collcommon_tonumkey(cc, numkey, ac-2, av+2, 1);
- ep->e_symkey = av[1].a_w.w_symbol;
- }
- }
- else if (av->a_type == A_SYMBOL && av[1].a_type == A_FLOAT)
- {
- if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &numkey, s))
- {
- if (ep = collcommon_numkey(cc, numkey))
- collcommon_remove(cc, ep);
- ep = collcommon_tosymkey(cc, av->a_w.w_symbol, ac-2, av+2, 1);
- ep->e_hasnumkey = 1;
- ep->e_numkey = numkey;
- }
+ if (!x->busy) {
+ if (ac >= 3)
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ int numkey;
+ if (av->a_type == A_FLOAT && av[1].a_type == A_SYMBOL)
+ {
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_symkey(cc, av[1].a_w.w_symbol))
+ collcommon_remove(cc, ep);
+ ep = collcommon_tonumkey(cc, numkey, ac-2, av+2, 1);
+ ep->e_symkey = av[1].a_w.w_symbol;
+ }
+ }
+ else if (av->a_type == A_SYMBOL && av[1].a_type == A_FLOAT)
+ {
+ if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_remove(cc, ep);
+ ep = collcommon_tosymkey(cc, av->a_w.w_symbol, ac-2, av+2, 1);
+ ep->e_hasnumkey = 1;
+ ep->e_numkey = numkey;
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
+ else loud_messarg((t_pd *)x, s);
}
- else loud_messarg((t_pd *)x, s);
- }
- else loud_messarg((t_pd *)x, s);
}
static void coll_insert(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac >= 2 && av->a_type == A_FLOAT)
- coll_tokey(x, av, ac-1, av+1, 0, s);
- else
- loud_messarg((t_pd *)x, s);
+ if (!x->busy) {
+ if (ac >= 2 && av->a_type == A_FLOAT)
+ coll_tokey(x, av, ac-1, av+1, 0, s);
+ else
+ loud_messarg((t_pd *)x, s);
+ }
}
static void coll_remove(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac)
- {
- t_collelem *ep;
- if (ep = coll_findkey(x, av, s))
- collcommon_remove(x->x_common, ep);
- }
- else loud_messarg((t_pd *)x, s);
+ if (!x->busy) {
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ collcommon_remove(x->x_common, ep);
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
}
static void coll_delete(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac)
- {
- t_collelem *ep;
- if (ep = coll_findkey(x, av, s))
- {
- if (av->a_type == A_FLOAT)
- {
- int numkey = ep->e_numkey;
- t_collelem *next;
- for (next = ep->e_next; next; next = next->e_next)
- if (next->e_hasnumkey && next->e_numkey > numkey)
- next->e_numkey--;
- }
- collcommon_remove(x->x_common, ep);
+ if (!x->busy) {
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ int numkey = ep->e_numkey;
+ t_collelem *next;
+ for (next = ep->e_next; next; next = next->e_next)
+ if (next->e_hasnumkey && next->e_numkey > numkey)
+ next->e_numkey--;
+ }
+ collcommon_remove(x->x_common, ep);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
}
- }
- else loud_messarg((t_pd *)x, s);
}
static void coll_assoc(t_coll *x, t_symbol *s, t_floatarg f)
{
- int numkey;
- if (loud_checkint((t_pd *)x, f, &numkey, gensym("assoc")))
- {
- t_collcommon *cc = x->x_common;
- t_collelem *ep1, *ep2;
- if ((ep1 = collcommon_numkey(cc, numkey)) &&
- ep1->e_symkey != s) /* LATER rethink */
- {
- if (ep2 = collcommon_symkey(cc, s))
- collcommon_remove(cc, ep2);
- collcommon_changesymkey(cc, ep1, s);
+ if (!x->busy) {
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, gensym("assoc")))
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep1, *ep2;
+ if ((ep1 = collcommon_numkey(cc, numkey)) &&
+ ep1->e_symkey != s) /* LATER rethink */
+ {
+ if (ep2 = collcommon_symkey(cc, s))
+ collcommon_remove(cc, ep2);
+ collcommon_changesymkey(cc, ep1, s);
+ }
+ }
}
- }
}
static void coll_deassoc(t_coll *x, t_symbol *s, t_floatarg f)
{
- int numkey;
- if (loud_checkint((t_pd *)x, f, &numkey, gensym("deassoc")))
- {
- t_collcommon *cc = x->x_common;
- t_collelem *ep;
- if (ep = collcommon_numkey(cc, numkey))
- collcommon_changesymkey(cc, ep, 0);
- }
+ if (!x->busy) {
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, gensym("deassoc")))
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_changesymkey(cc, ep, 0);
+ }
+ }
}
static void coll_subsym(t_coll *x, t_symbol *s1, t_symbol *s2)
{
- t_collelem *ep;
- if (s1 != s2 && (ep = collcommon_symkey(x->x_common, s2)))
- collcommon_changesymkey(x->x_common, ep, s1);
+ if (!x->busy) {
+ t_collelem *ep;
+ if (s1 != s2 && (ep = collcommon_symkey(x->x_common, s2)))
+ collcommon_changesymkey(x->x_common, ep, s1);
+ }
}
static void coll_renumber(t_coll *x, t_floatarg f)
{
- int startkey;
- if (loud_checkint((t_pd *)x, f, &startkey, gensym("renumber")))
- collcommon_renumber(x->x_common, startkey);
+ if (!x->busy) {
+ int startkey;
+ if (loud_checkint((t_pd *)x, f, &startkey, gensym("renumber")))
+ collcommon_renumber(x->x_common, startkey);
+ }
}
static void coll_merge(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac >= 2)
- {
- t_collcommon *cc = x->x_common;
- t_collelem *ep;
- if (av->a_type == A_FLOAT)
- {
- int numkey;
- if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
- {
- if (ep = collcommon_numkey(cc, numkey))
- collcommon_adddata(cc, ep, ac-1, av+1);
- else /* LATER consider defining collcommon_toclosest() */
- collcommon_tonumkey(cc, numkey, ac-1, av+1, 1);
- }
- }
- else if (av->a_type == A_SYMBOL)
- {
- if (ep = collcommon_symkey(cc, av->a_w.w_symbol))
- collcommon_adddata(cc, ep, ac-1, av+1);
- else
- {
- ep = collelem_new(ac-1, av+1, 0, av->a_w.w_symbol);
- collcommon_putafter(cc, ep, cc->c_last);
- }
+ if (!x->busy) {
+ if (ac >= 2)
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (av->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_adddata(cc, ep, ac-1, av+1);
+ else /* LATER consider defining collcommon_toclosest() */
+ collcommon_tonumkey(cc, numkey, ac-1, av+1, 1);
+ }
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (ep = collcommon_symkey(cc, av->a_w.w_symbol))
+ collcommon_adddata(cc, ep, ac-1, av+1);
+ else
+ {
+ ep = collelem_new(ac-1, av+1, 0, av->a_w.w_symbol);
+ collcommon_putafter(cc, ep, cc->c_last);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
+ else loud_messarg((t_pd *)x, s);
}
- else loud_messarg((t_pd *)x, s);
- }
- else loud_messarg((t_pd *)x, s);
}
static void coll_sub(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac)
- {
- t_collelem *ep;
- if (ep = coll_findkey(x, av, s))
- {
- t_collcommon *cc = x->x_common;
- t_atom *key = av++;
- ac--;
- while (ac >= 2)
- {
- if (av->a_type == A_FLOAT)
+ if (!x->busy) {
+ if (ac)
{
- int ndx;
- if (loud_checkint((t_pd *)x, av->a_w.w_float, &ndx, 0)
- && ndx >= 1 && ndx <= ep->e_size)
- ep->e_data[ndx-1] = av[1];
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ {
+ t_collcommon *cc = x->x_common;
+ t_atom *key = av++;
+ ac--;
+ while (ac >= 2)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ int ndx;
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &ndx, 0)
+ && ndx >= 1 && ndx <= ep->e_size)
+ ep->e_data[ndx-1] = av[1];
+ }
+ ac -= 2;
+ av += 2;
+ }
+ if (s == gensym("sub"))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = coll_findkey(x, key, 0)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ }
}
- ac -= 2;
- av += 2;
- }
- if (s == gensym("sub"))
- {
- coll_keyoutput(x, ep);
- if (!cc->c_selfmodified || (ep = coll_findkey(x, key, 0)))
- coll_dooutput(x, ep->e_size, ep->e_data);
- }
+ else loud_messarg((t_pd *)x, s);
}
- }
- else loud_messarg((t_pd *)x, s);
}
static void coll_sort(t_coll *x, t_floatarg f1, t_floatarg f2)
{
+
int dir, ndx;
if (loud_checkint((t_pd *)x, f1, &dir, gensym("sort")) &&
loud_checkint((t_pd *)x, f2, &ndx, gensym("sort")))
@@ -1197,14 +1384,16 @@
needed in case of their implementation... */
static void coll_swap(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac == 2)
- {
- t_collelem *ep1, *ep2;
- if ((ep1 = coll_findkey(x, av, s)) &&
- (ep2 = coll_findkey(x, av + 1, s)))
- collcommon_swapkeys(x->x_common, ep1, ep2);
- }
- else loud_messarg((t_pd *)x, s);
+ if (!x->busy) {
+ if (ac == 2)
+ {
+ t_collelem *ep1, *ep2;
+ if ((ep1 = coll_findkey(x, av, s)) &&
+ (ep2 = coll_findkey(x, av + 1, s)))
+ collcommon_swapkeys(x->x_common, ep1, ep2);
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
}
/* CHECKED traversal direction change is consistent with the general rule:
@@ -1216,212 +1405,276 @@
static void coll_next(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- if (cc->c_headstate != COLL_HEADRESET &&
- cc->c_headstate != COLL_HEADDELETED) /* asymmetric, LATER rethink */
- {
- if (cc->c_head)
- cc->c_head = cc->c_head->e_next;
- if (!cc->c_head && !(cc->c_head = cc->c_first)) /* CHECKED wrapping */
- return;
- }
- else if (!cc->c_head && !(cc->c_head = cc->c_first))
- return;
- cc->c_headstate = COLL_HEADNEXT;
- coll_keyoutput(x, cc->c_head);
- if (cc->c_head)
- coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
- else if (!cc->c_selfmodified)
- loudbug_bug("coll_next"); /* LATER rethink */
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ if (cc->c_headstate != COLL_HEADRESET &&
+ cc->c_headstate != COLL_HEADDELETED) /* asymmetric, LATER rethink */
+ {
+ if (cc->c_head)
+ cc->c_head = cc->c_head->e_next;
+ if (!cc->c_head && !(cc->c_head = cc->c_first)) /* CHECKED wrapping */
+ return;
+ }
+ else if (!cc->c_head && !(cc->c_head = cc->c_first))
+ return;
+ cc->c_headstate = COLL_HEADNEXT;
+ coll_keyoutput(x, cc->c_head);
+ if (cc->c_head)
+ coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
+ else if (!cc->c_selfmodified)
+ loudbug_bug("coll_next"); /* LATER rethink */
+ }
}
static void coll_prev(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- if (cc->c_headstate != COLL_HEADRESET)
- {
- if (cc->c_head)
- cc->c_head = cc->c_head->e_prev;
- if (!cc->c_head && !(cc->c_head = cc->c_last)) /* CHECKED wrapping */
- return;
- }
- else if (!cc->c_head && !(cc->c_head = cc->c_first))
- return;
- cc->c_headstate = COLL_HEADPREV;
- coll_keyoutput(x, cc->c_head);
- if (cc->c_head)
- coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
- else if (!cc->c_selfmodified)
- loudbug_bug("coll_prev"); /* LATER rethink */
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ if (cc->c_headstate != COLL_HEADRESET)
+ {
+ if (cc->c_head)
+ cc->c_head = cc->c_head->e_prev;
+ if (!cc->c_head && !(cc->c_head = cc->c_last)) /* CHECKED wrapping */
+ return;
+ }
+ else if (!cc->c_head && !(cc->c_head = cc->c_first))
+ return;
+ cc->c_headstate = COLL_HEADPREV;
+ coll_keyoutput(x, cc->c_head);
+ if (cc->c_head)
+ coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
+ else if (!cc->c_selfmodified)
+ loudbug_bug("coll_prev"); /* LATER rethink */
+ }
}
static void coll_end(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- cc->c_head = cc->c_last;
- cc->c_headstate = COLL_HEADRESET;
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ cc->c_head = cc->c_last;
+ cc->c_headstate = COLL_HEADRESET;
+ }
}
static void coll_goto(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac)
- {
- t_collelem *ep = coll_findkey(x, av, s);
- if (ep)
- {
- t_collcommon *cc = x->x_common;
- cc->c_head = ep;
- cc->c_headstate = COLL_HEADRESET;
+ if (!x->busy) {
+ if (ac)
+ {
+ t_collelem *ep = coll_findkey(x, av, s);
+ if (ep)
+ {
+ t_collcommon *cc = x->x_common;
+ cc->c_head = ep;
+ cc->c_headstate = COLL_HEADRESET;
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
}
- }
- else loud_messarg((t_pd *)x, s);
}
static void coll_nth(t_coll *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac >= 2 && av[1].a_type == A_FLOAT)
- {
- int ndx;
- t_collelem *ep;
- if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &ndx, s) &&
- (ep = coll_findkey(x, av, s)) &&
- ep->e_size >= ndx)
- {
- t_atom *ap = ep->e_data + --ndx;
- if (ap->a_type == A_FLOAT)
- outlet_float(((t_object *)x)->ob_outlet, ap->a_w.w_float);
- else if (ap->a_type == A_SYMBOL)
- outlet_symbol(((t_object *)x)->ob_outlet, ap->a_w.w_symbol);
+ if (!x->busy) {
+ if (ac >= 2 && av[1].a_type == A_FLOAT)
+ {
+ int ndx;
+ t_collelem *ep;
+ if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &ndx, s) &&
+ (ep = coll_findkey(x, av, s)) &&
+ ep->e_size >= ndx)
+ {
+ t_atom *ap = ep->e_data + --ndx;
+ if (ap->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, ap->a_w.w_float);
+ else if (ap->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, ap->a_w.w_symbol);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
}
- }
- else loud_messarg((t_pd *)x, s);
}
static void coll_length(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- t_collelem *ep = cc->c_first;
- int result = 0;
- while (ep) result++, ep = ep->e_next;
- outlet_float(((t_object *)x)->ob_outlet, result);
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = cc->c_first;
+ int result = 0;
+ while (ep) result++, ep = ep->e_next;
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
}
static void coll_min(t_coll *x, t_floatarg f)
{
- int ndx;
- if (loud_checkint((t_pd *)x, f, &ndx, gensym("min")))
- {
- t_collelem *found;
- if (ndx > 0)
- ndx--;
- /* LATER consider complaining: */
- else if (ndx < 0)
- return; /* CHECKED silently rejected */
- /* else CHECKED silently defaults to 1 */
- if (found = coll_firsttyped(x, ndx, A_FLOAT))
- {
- t_float result = found->e_data[ndx].a_w.w_float;
- t_collelem *ep;
- for (ep = found->e_next; ep; ep = ep->e_next)
- {
- if (ep->e_size > ndx &&
- ep->e_data[ndx].a_type == A_FLOAT &&
- ep->e_data[ndx].a_w.w_float < result)
+ if (!x->busy) {
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, gensym("min")))
{
- found = ep;
- result = ep->e_data[ndx].a_w.w_float;
+ t_collelem *found;
+ if (ndx > 0)
+ ndx--;
+ /* LATER consider complaining: */
+ else if (ndx < 0)
+ return; /* CHECKED silently rejected */
+ /* else CHECKED silently defaults to 1 */
+ if (found = coll_firsttyped(x, ndx, A_FLOAT))
+ {
+ t_float result = found->e_data[ndx].a_w.w_float;
+ t_collelem *ep;
+ for (ep = found->e_next; ep; ep = ep->e_next)
+ {
+ if (ep->e_size > ndx &&
+ ep->e_data[ndx].a_type == A_FLOAT &&
+ ep->e_data[ndx].a_w.w_float < result)
+ {
+ found = ep;
+ result = ep->e_data[ndx].a_w.w_float;
+ }
+ }
+ coll_keyoutput(x, found);
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
}
- }
- coll_keyoutput(x, found);
- outlet_float(((t_object *)x)->ob_outlet, result);
}
- }
}
static void coll_max(t_coll *x, t_floatarg f)
{
- int ndx;
- if (loud_checkint((t_pd *)x, f, &ndx, gensym("max")))
- {
- t_collelem *found;
- if (ndx > 0)
- ndx--;
- /* LATER consider complaining: */
- else if (ndx < 0)
- return; /* CHECKED silently rejected */
- /* else CHECKED silently defaults to 1 */
- if (found = coll_firsttyped(x, ndx, A_FLOAT))
- {
- t_float result = found->e_data[ndx].a_w.w_float;
- t_collelem *ep;
- for (ep = found->e_next; ep; ep = ep->e_next)
- {
- if (ep->e_size > ndx &&
- ep->e_data[ndx].a_type == A_FLOAT &&
- ep->e_data[ndx].a_w.w_float > result)
+ if (!x->busy) {
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, gensym("max")))
{
- found = ep;
- result = ep->e_data[ndx].a_w.w_float;
+ t_collelem *found;
+ if (ndx > 0)
+ ndx--;
+ /* LATER consider complaining: */
+ else if (ndx < 0)
+ return; /* CHECKED silently rejected */
+ /* else CHECKED silently defaults to 1 */
+ if (found = coll_firsttyped(x, ndx, A_FLOAT))
+ {
+ t_float result = found->e_data[ndx].a_w.w_float;
+ t_collelem *ep;
+ for (ep = found->e_next; ep; ep = ep->e_next)
+ {
+ if (ep->e_size > ndx &&
+ ep->e_data[ndx].a_type == A_FLOAT &&
+ ep->e_data[ndx].a_w.w_float > result)
+ {
+ found = ep;
+ result = ep->e_data[ndx].a_w.w_float;
+ }
+ }
+ coll_keyoutput(x, found);
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
}
- }
- coll_keyoutput(x, found);
- outlet_float(((t_object *)x)->ob_outlet, result);
}
- }
}
static void coll_refer(t_coll *x, t_symbol *s)
{
- if (!coll_rebind(x, s))
- {
- /* LATER consider complaining */
- }
+ if (!x->busy) {
+ if (!coll_rebind(x, s))
+ {
+ /* LATER consider complaining */
+ }
+ }
}
static void coll_flags(t_coll *x, t_float f1, t_float f2)
{
- int i1;
- if (loud_checkint((t_pd *)x, f1, &i1, gensym("flags")))
- {
- t_collcommon *cc = x->x_common;
- cc->c_embedflag = (i1 != 0);
- }
+ if (!x->busy) {
+ int i1;
+ if (loud_checkint((t_pd *)x, f1, &i1, gensym("flags")))
+ {
+ t_collcommon *cc = x->x_common;
+ cc->c_embedflag = (i1 != 0);
+ }
+ }
}
static void coll_read(t_coll *x, t_symbol *s)
{
- t_collcommon *cc = x->x_common;
- if (s && s != &s_)
- collcommon_doread(cc, s, x->x_canvas);
- else
- hammerpanel_open(cc->c_filehandle, 0);
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ if (s && s != &s_) {
+ // spawn separate thread to avoid xruns
+ t_threadedFunctionParams rPars;
+ rPars.x = x;
+ rPars.cc = cc;
+ rPars.fn = s;
+ rPars.cv = x->x_canvas;
+ x->busy = 1;
+ pthread_create( &x->unsafer_t, &x->unsafe_attr, (void *) &coll_threadedread, (void *) &rPars);
+ //collcommon_doread(cc, s, x->x_canvas);
+ }
+ else
+ hammerpanel_open(cc->c_filehandle, 0);
+ }
}
static void coll_write(t_coll *x, t_symbol *s)
{
- t_collcommon *cc = x->x_common;
- if (s && s != &s_)
- collcommon_dowrite(cc, s, x->x_canvas);
- else
- hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKED no default name */
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ if (s && s != &s_) {
+ // spawn separate thread to avoid xruns
+ t_threadedFunctionParams rPars;
+ rPars.x = x;
+ rPars.cc = cc;
+ rPars.fn = s;
+ rPars.cv = x->x_canvas;
+ x->busy = 1;
+ pthread_create( &x->unsafew_t, &x->unsafe_attr, (void *) &coll_threadedwrite, (void *) &rPars);
+ //collcommon_dowrite(cc, s, x->x_canvas);
+ }
+ else
+ hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKED no default name */
+ }
}
static void coll_readagain(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- if (cc->c_filename)
- collcommon_doread(cc, 0, 0);
- else
- hammerpanel_open(cc->c_filehandle, 0);
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ if (cc->c_filename) {
+ // spawn separate thread to avoid xruns
+ t_threadedFunctionParams rPars;
+ rPars.x = x;
+ rPars.cc = cc;
+ rPars.fn = 0;
+ rPars.cv = 0;
+ x->busy = 1;
+ pthread_create( &x->unsafer_t, &x->unsafe_attr, (void *) &coll_threadedread, (void *) &rPars);
+ //collcommon_doread(cc, 0, 0);
+ }
+ else
+ hammerpanel_open(cc->c_filehandle, 0);
+ }
}
static void coll_writeagain(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- if (cc->c_filename)
- collcommon_dowrite(cc, 0, 0);
- else
- hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKED no default name */
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ if (cc->c_filename) {
+ // spawn separate thread to avoid xruns
+ t_threadedFunctionParams rPars;
+ rPars.x = x;
+ rPars.cc = cc;
+ rPars.fn = 0;
+ rPars.cv = 0;
+ x->busy = 1;
+ pthread_create( &x->unsafew_t, &x->unsafe_attr, (void *) &coll_threadedwrite, (void *) &rPars);
+ //collcommon_dowrite(cc, 0, 0);
+ }
+ else
+ hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKED no default name */
+ }
}
static void coll_filetype(t_coll *x, t_symbol *s)
@@ -1431,17 +1684,19 @@
static void coll_dump(t_coll *x)
{
- t_collcommon *cc = x->x_common;
- t_collelem *ep;
- for (ep = cc->c_first; ep; ep = ep->e_next)
- {
- coll_keyoutput(x, ep);
- if (cc->c_selfmodified)
- break;
- coll_dooutput(x, ep->e_size, ep->e_data);
- /* FIXME dooutput() may invalidate ep as well as keyoutput()... */
- }
- outlet_bang(x->x_dumpbangout);
+ if (!x->busy) {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ coll_keyoutput(x, ep);
+ if (cc->c_selfmodified)
+ break;
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ /* FIXME dooutput() may invalidate ep as well as keyoutput()... */
+ }
+ outlet_bang(x->x_dumpbangout);
+ }
}
static void coll_open(t_coll *x)
@@ -1492,15 +1747,17 @@
#ifdef COLL_DEBUG
static void collelem_post(t_collelem *ep)
{
- if (ep->e_hasnumkey && ep->e_symkey)
- loudbug_startpost("%d %s:", ep->e_numkey, ep->e_symkey->s_name);
- else if (ep->e_hasnumkey)
- loudbug_startpost("%d:", ep->e_numkey);
- else if (ep->e_symkey)
- loudbug_startpost("%s:", ep->e_symkey->s_name);
- else loudbug_bug("collcommon_post");
- loudbug_postatom(ep->e_size, ep->e_data);
- loudbug_endpost();
+ if (!x->busy) {
+ if (ep->e_hasnumkey && ep->e_symkey)
+ loudbug_startpost("%d %s:", ep->e_numkey, ep->e_symkey->s_name);
+ else if (ep->e_hasnumkey)
+ loudbug_startpost("%d:", ep->e_numkey);
+ else if (ep->e_symkey)
+ loudbug_startpost("%s:", ep->e_symkey->s_name);
+ else loudbug_bug("collcommon_post");
+ loudbug_postatom(ep->e_size, ep->e_data);
+ loudbug_endpost();
+ }
}
static void collcommon_post(t_collcommon *cc)
@@ -1511,18 +1768,20 @@
static void coll_debug(t_coll *x, t_floatarg f)
{
- t_collcommon *cc = coll_checkcommon(x);
- if (cc)
- {
- t_coll *x1 = cc->c_refs;
- t_collelem *ep, *last;
- int i = 0;
- while (x1) i++, x1 = x1->x_next;
- loudbug_post("refcount %d", i);
- for (ep = cc->c_first, last = 0; ep; ep = ep->e_next) last = ep;
- if (last != cc->c_last) loudbug_bug("coll_debug: last element");
- collcommon_post(cc);
- }
+ if (!x->busy) {
+ t_collcommon *cc = coll_checkcommon(x);
+ if (cc)
+ {
+ t_coll *x1 = cc->c_refs;
+ t_collelem *ep, *last;
+ int i = 0;
+ while (x1) i++, x1 = x1->x_next;
+ loudbug_post("refcount %d", i);
+ for (ep = cc->c_first, last = 0; ep; ep = ep->e_next) last = ep;
+ if (last != cc->c_last) loudbug_bug("coll_debug: last element");
+ collcommon_post(cc);
+ }
+ }
}
#endif
@@ -1541,7 +1800,20 @@
x->x_filebangout = outlet_new((t_object *)x, &s_bang);
x->x_dumpbangout = outlet_new((t_object *)x, &s_bang);
x->x_filehandle = hammerfile_new((t_pd *)x, coll_embedhook, 0, 0, 0);
+ x->busy = 0;
coll_bind(x, s);
+
+ //prep threading stuff
+ pthread_attr_setdetachstate(&x->unsafe_attr, PTHREAD_CREATE_DETACHED);
+ x->x_clock = clock_new(x, (t_method)coll_tick);
+
+ //call dummy_init function to create dummy thread
+ //which always trips that first xrun so that we
+ //can take care of this at creation time rather
+ //than having to deal with xruns at runtime
+ x->x_init = clock_new(x, (t_method)coll_dummy_init);
+ clock_delay(x->x_init, 0);
+
return (x);
}
_______________________________________________
Pd-dev mailing list
[email protected]
http://lists.puredata.info/listinfo/pd-dev