Oops, please use the attached patch instead. Best wishes,
Ico On Sat, 2010-09-25 at 12:36 -0400, Ivica Ico Bukvic wrote: > 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 19:33:38.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,51 @@ t_outlet *x_filebangout; t_outlet *x_dumpbangout; struct _coll *x_next; + + //for thread-unsafe file i/o operations + //added by Ivica Ico Bukvic <i...@vt.edu> 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 +243,8 @@ } } + + /* atomic collcommon modifiers: clearall, remove, replace, putbefore, putafter, swaplinks, swapkeys, changesymkey, renumber, sort */ @@ -582,6 +626,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 +784,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 +1107,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 +1382,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 +1403,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 +1682,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 +1745,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 +1766,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 +1798,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-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list