Hmm.. I'm still looking for a solution that doesn't require adding extra stuff to bindlist_bang() etc.
cheers M
On Wed, Jun 20, 2012 at 06:09:22PM -0400, Ivica Ico Bukvic wrote:
On 06/20/2012 05:38 PM, Miller Puckette wrote:
[snip] I'm just saying that the automatic varable t_bindelem *e should be declared at the beginning of the block - no worries about change_bindlist_via_graph.
Ah, now I get it :-). Fixed.
I think bindlist_bang() etc are more critical than pd_unbind as they naturally get called many times while a patch is running whereas pd_unbind is typically called only when objects are deleted. So moving checks from pd_unbind() to bindlist_bang() etc decreases pd's run-time efficiency.
cheers M
OK, how about the attached patch where now I use the change_bindlist_via_graph variable and increment it by one every time something needs to be unbound so when you return back to the bindlist_bang() or whatever call was issued, only if change_bindlist_via_graph > 1 should it call unbind. Now it avoids entering the bindlist_cleanup unless it absolutely has to...
Attached is also a patch that illustrates your case presented earlier which crashed pd-l2ork prior to applying this latest version of the patch.
Cheers!
-- Ivica Ico Bukvic, D.M.A Composition, Music Technology Director, DISIS Interactive Sound& Intermedia Studio Director, L2Ork Linux Laptop Orchestra Head, ICAT IMPACT Studio Virginia Tech Department of Music Blacksburg, VA 24061-0240 (540) 231-6139 (540) 231-5034 (fax) disis.music.vt.edu l2ork.music.vt.edu ico.bukvic.net
--- m_pd.c.old 2012-06-20 17:51:43.845040884 -0400 +++ m_pd.c 2012-06-20 18:06:02.047009570 -0400 @@ -146,48 +146,101 @@ t_bindelem *b_list; } t_bindlist;
+static int change_bindlist_via_graph = 0;
+static void bindlist_cleanup(t_bindlist *x) +{
- //fprintf(stderr,"bindlist_cleanup\n");
- t_bindelem *e, *e2;
- if (x->b_list->e_who == NULL)
- {
e = x->b_list;
x->b_list = e->e_next;
freebytes(e, sizeof(t_bindelem));
//fprintf(stderr,"success B1a\n");
- }
- for (e = x->b_list; e2 = e->e_next; e = e2)
if (e2->e_who == NULL)
- {
e->e_next = e2->e_next;
freebytes(e2, sizeof(t_bindelem));
//fprintf(stderr,"success B1b\n");
break;
- }
- if (!x->b_list->e_next)
- {
freebytes(x->b_list, sizeof(t_bindelem));
pd_free(&x->b_pd);
//fprintf(stderr,"success B2\n");
- }
+}
static void bindlist_bang(t_bindlist *x) { t_bindelem *e;
- change_bindlist_via_graph = 1; for (e = x->b_list; e; e = e->e_next)
pd_bang(e->e_who);
if (e->e_who != NULL) pd_bang(e->e_who);
- if (change_bindlist_via_graph > 1)
bindlist_cleanup(x);
- change_bindlist_via_graph = 0;
}
static void bindlist_float(t_bindlist *x, t_float f) { t_bindelem *e;
- change_bindlist_via_graph = 1; for (e = x->b_list; e; e = e->e_next)
pd_float(e->e_who, f);
if (e->e_who != NULL) pd_float(e->e_who, f);
- if (change_bindlist_via_graph > 1)
bindlist_cleanup(x);
- change_bindlist_via_graph = 0;
}
static void bindlist_symbol(t_bindlist *x, t_symbol *s) { t_bindelem *e;
- change_bindlist_via_graph = 1; for (e = x->b_list; e; e = e->e_next)
pd_symbol(e->e_who, s);
if (e->e_who != NULL) pd_symbol(e->e_who, s);
- if (change_bindlist_via_graph > 1)
bindlist_cleanup(x);
- change_bindlist_via_graph = 0;
}
static void bindlist_pointer(t_bindlist *x, t_gpointer *gp) { t_bindelem *e;
- change_bindlist_via_graph = 1; for (e = x->b_list; e; e = e->e_next)
pd_pointer(e->e_who, gp);
if (e->e_who != NULL) pd_pointer(e->e_who, gp);
- if (change_bindlist_via_graph > 1)
bindlist_cleanup(x);
- change_bindlist_via_graph = 0;
}
static void bindlist_list(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) { t_bindelem *e;
- change_bindlist_via_graph = 1; for (e = x->b_list; e; e = e->e_next)
pd_list(e->e_who, s, argc, argv);
if (e->e_who != NULL) pd_list(e->e_who, s, argc, argv);
- if (change_bindlist_via_graph > 1)
bindlist_cleanup(x);
- change_bindlist_via_graph = 0;
}
static void bindlist_anything(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) { t_bindelem *e;
- change_bindlist_via_graph = 1; for (e = x->b_list; e; e = e->e_next)
pd_typedmess(e->e_who, s, argc, argv);
if (e->e_who != NULL) pd_typedmess(e->e_who, s, argc, argv);
- if (change_bindlist_via_graph > 1)
bindlist_cleanup(x);
- change_bindlist_via_graph = 0;
}
void m_pd_setup(void) @@ -204,6 +257,7 @@
void pd_bind(t_pd *x, t_symbol *s) {
- //fprintf(stderr,"pd_bind %s\n", s->s_name); if (s->s_thing) { if (*s->s_thing == bindlist_class)
@@ -217,7 +271,7 @@ } else {
//fprintf(stderr,"pd_unbind option 1B %lx\n", (t_int)x);
//fprintf(stderr,"pd_bind option 1B %lx\n", (t_int)x); t_bindlist *b = (t_bindlist *)pd_new(bindlist_class); t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem)); t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem));
@@ -237,6 +291,7 @@
void pd_unbind(t_pd *x, t_symbol *s) {
- //fprintf(stderr,"pd_unbind %s\n", s->s_name); if (s->s_thing == x) { //fprintf(stderr,"pd_unbind option A %lx\n", (t_int)x); s->s_thing = 0;
@@ -247,30 +302,56 @@ goes down to one, get rid of the bindlist and bind the symbol straight to the remaining element. */
/* in pd-l2ork, we however also check whether changes to the bindlist
occur via graph (through code execution, e.g. dynamic change of receives)
and if so, we do not deallocate memory until the entire bindlist_<datatype>
function is complete with its execution, after which we call
bindlist_cleanup(). we control the execution via static int variable
change_bindlist_via_graph */
//fprintf(stderr,"pd_unbind option B %lx\n", (t_int)x);
t_bindlist *b = (t_bindlist *)s->s_thing; t_bindelem *e, *e2; if ((e = b->b_list)->e_who == x) {
b->b_list = e->e_next;
freebytes(e, sizeof(t_bindelem));
if (change_bindlist_via_graph) {
change_bindlist_via_graph++;
e->e_who = NULL;
} else {
b->b_list = e->e_next;
freebytes(e, sizeof(t_bindelem));
} //fprintf(stderr,"success B1a\n"); } else for (e = b->b_list; e2 = e->e_next; e = e2) if (e2->e_who == x) {
e->e_next = e2->e_next;
freebytes(e2, sizeof(t_bindelem));
if (change_bindlist_via_graph) {
change_bindlist_via_graph++;
e2->e_who = NULL;
} else {
e->e_next = e2->e_next;
freebytes(e2, sizeof(t_bindelem));
} //fprintf(stderr,"success B1b\n"); break; }
if (!b->b_list->e_next)
int count_valid = 0;
for (e = b->b_list; e; e = e->e_next) {
if (e->e_who != NULL)
count_valid++;
}
if (count_valid == 1) { s->s_thing = b->b_list->e_who;
freebytes(b->b_list, sizeof(t_bindelem));
pd_free(&b->b_pd);
///fprintf(stderr,"success B3\n");
if (!change_bindlist_via_graph) {
freebytes(b->b_list, sizeof(t_bindelem));
pd_free(&b->b_pd);
}
} else pd_error(x, "%s: couldn't unbind", s->s_name);//fprintf(stderr,"success B2\n"); }