[PD] variable receive objects?

Ivica Ico Bukvic ico at vt.edu
Mon May 28 07:07:30 CEST 2012


On 05/28/2012 12:10 AM, Ivica Ico Bukvic wrote:
> Never mind. Just had a look at pd_bind/unbind code. This makes me 
> wonder what if all bindings/unbindings were handled as lists? Would 
> this potentially break anything (other than having to modify 
> bind/unbind mechanism)? Does anything else depend on 2-member list vs. 
> 1-member pointer in terms of bindings? I suspect there would be some 
> cpu impact on having it implemented this way, but not that much.
>
Actually, please try attached patch. It fixes all such crashes for me on 
pd-l2ork. Basically it has a static variable set within m_pd.c that is 
turned on only when one of bindlist_<var>() functions is called in which 
case any potential memory deallocation calls within pd_unbind are 
deferred until all members of bindlist->b_list have been served with 
data. After that bindlist_cleanup does its thing based on which members 
have e_who pointing to NULL and that's that. In the event a call arrives 
outside those bindlist_<var>() functions, it immediately deallocates 
stuff as is currently the case with pd vanilla and extended.

Potential caveat: if one somehow invokes an event outside regular 
execution of the code and it somehow arrives exactly during that narrow 
span of time when the static var is enabled, its memory deallocation 
will be ignored. I am however unsure if this is theoretically even 
possible since my understanding is that the graph is never being 
executed out-of-sync. Please correct me if I am wrong.

Cheers!

-- 
Ivica Ico Bukvic, D.M.A
Composition, Music Technology
Director, DISIS Interactive Sound&  Intermedia Studio
Director, L2Ork Linux Laptop Orchestra
Head, ICAT Integrative Performance 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

-------------- next part --------------
--- m_pd.c.old	2012-05-28 00:55:52.616612895 -0400
+++ m_pd.c.new	2012-05-28 00:58:47.514606515 -0400
@@ -146,48 +146,95 @@
     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)
 {
+	change_bindlist_via_graph = 1;
     t_bindelem *e;
     for (e = x->b_list; e; e = e->e_next)
         pd_bang(e->e_who);
+	bindlist_cleanup(x);
+	change_bindlist_via_graph = 0;
 }
 
 static void bindlist_float(t_bindlist *x, t_float f)
 {
+	change_bindlist_via_graph = 1;
     t_bindelem *e;
     for (e = x->b_list; e; e = e->e_next)
         pd_float(e->e_who, f);
+	bindlist_cleanup(x);
+	change_bindlist_via_graph = 0;
 }
 
 static void bindlist_symbol(t_bindlist *x, t_symbol *s)
 {
+	change_bindlist_via_graph = 1;
     t_bindelem *e;
     for (e = x->b_list; e; e = e->e_next)
         pd_symbol(e->e_who, s);
+	bindlist_cleanup(x);
+	change_bindlist_via_graph = 0;
 }
 
 static void bindlist_pointer(t_bindlist *x, t_gpointer *gp)
 {
+	change_bindlist_via_graph = 1;
     t_bindelem *e;
     for (e = x->b_list; e; e = e->e_next)
         pd_pointer(e->e_who, gp);
+	bindlist_cleanup(x);
+	change_bindlist_via_graph = 0;
 }
 
 static void bindlist_list(t_bindlist *x, t_symbol *s,
     int argc, t_atom *argv)
 {
+	change_bindlist_via_graph = 1;
     t_bindelem *e;
     for (e = x->b_list; e; e = e->e_next)
         pd_list(e->e_who, s, argc, argv);
+	bindlist_cleanup(x);
+	change_bindlist_via_graph = 0;
 }
 
 static void bindlist_anything(t_bindlist *x, t_symbol *s,
     int argc, t_atom *argv)
 {
+	change_bindlist_via_graph = 1;
     t_bindelem *e;
     for (e = x->b_list; e; e = e->e_next)
         pd_typedmess(e->e_who, s, argc, argv);
+	bindlist_cleanup(x);
+	change_bindlist_via_graph = 0;
 }
 
 void m_pd_setup(void)
@@ -247,29 +294,53 @@
             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)
+				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) 
+				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);
+			if (!change_bindlist_via_graph) {
+            	freebytes(b->b_list, sizeof(t_bindelem));
+            	pd_free(&b->b_pd);
+			}
 			//fprintf(stderr,"success B2\n");
         }
     }


More information about the Pd-list mailing list