Commits

Armin Rigo committed e8a39aa

Random progress.

Comments (0)

Files changed (3)

pypy/translator/c/src/stacklet/stacklet.c

 
 /************************************************************/
 
+struct cap_loc_s {
+    char **cl_original_pointer;
+    struct stacklet_s **cl_contained_in_stacklet;
+    struct cap_loc_s *cl_next;
+}
+
 struct stacklet_s {
-    stacklet_id id;    /* first field */
-
     /* The portion of the real stack claimed by this paused tealet. */
     char *stack_start;                /* the "near" end of the stack */
     char *stack_stop;                 /* the "far" end of the stack */
      * main stack.
      */
     struct stacklet_s *stack_prev;
+
+    /* the captured stack locations */
+    struct cap_loc_s *stack_cap_locs;
 };
 
 void *(*_stacklet_switchstack)(void*(*)(void*, void*),
 void (*_stacklet_initialstub)(struct stacklet_thread_s *,
                               stacklet_run_fn, void *) = NULL;
 
-struct stacklet_id_s {
-    stacklet_handle stacklet;
-};
-
 struct stacklet_thread_s {
-    stacklet_id g_current_id;             /* first field */
     struct stacklet_s *g_stack_chain_head;  /* NULL <=> running main */
     char *g_current_stack_stop;
     char *g_current_stack_marker;
     struct stacklet_s *g_source;
     struct stacklet_s *g_target;
-    struct stacklet_id_s g_main_id;
+    struct stacklet_thread_s *g_prev_thread, *g_next_thread;
 };
 
+/* circular doubly-linked list */
+static struct stacklet_thread_s *g_all_threads = NULL;
+
 /***************************************************************/
 
 static void g_save(struct stacklet_s* g, char* stop
         return -1;
 
     stacklet = thrd->g_source;
-    stacklet->id = thrd->g_current_id;
-    stacklet->id->stacklet = stacklet;
     stacklet->stack_start = old_stack_pointer;
     stacklet->stack_stop  = thrd->g_current_stack_stop;
     stacklet->stack_saved = 0;
     memcpy(g->stack_start - stack_saved, g+1, stack_saved);
 #endif
     thrd->g_current_stack_stop = g->stack_stop;
-    thrd->g_current_id = g->id;
-    thrd->g_current_id->stacklet = NULL;
     free(g);
     return EMPTY_STACKLET_HANDLE;
 }
                           stacklet_run_fn run, void *run_arg)
 {
     struct stacklet_s *result;
-    stacklet_id sid1 = thrd->g_current_id;
+    /*stacklet_id sid1 = thrd->g_current_id;
     stacklet_id sid = malloc(sizeof(struct stacklet_id_s));
     if (sid == NULL) {
         thrd->g_source = NULL;
         return;
-    }
+        }*/
 
     /* The following call returns twice! */
     result = (struct stacklet_s *) _stacklet_switchstack(g_initial_save_state,
     if (result == NULL) {
         /* First time it returns. */
         if (thrd->g_source == NULL) {     /* out of memory */
-            free(sid);
+            /*free(sid);*/
             return;
         }
         /* Only g_initial_save_state() has run and has created 'g_source'.
            Call run(). */
-        sid->stacklet = NULL;
-        thrd->g_current_id = sid;
+        /*sid->stacklet = NULL;
+          thrd->g_current_id = sid;*/
         thrd->g_current_stack_stop = thrd->g_current_stack_marker;
         result = run(thrd->g_source, run_arg);
 
         /* Then switch to 'result'. */
-        free(sid);
+        /*free(sid);*/
         thrd->g_target = result;
         _stacklet_switchstack(g_destroy_state, g_restore_state, thrd);
 
         abort();
     }
     /* The second time it returns. */
-    assert(thrd->g_current_id == sid1);
+    /*assert(thrd->g_current_id == sid1);*/
 }
 
 /************************************************************/
     thrd = malloc(sizeof(struct stacklet_thread_s));
     if (thrd != NULL) {
         memset(thrd, 0, sizeof(struct stacklet_thread_s));
-        thrd->g_current_id = &thrd->g_main_id;
+        if (g_all_threads == NULL) {
+            g_all_threads = thrd;
+            thrd->g_prev_thread = thrd;
+            thrd->g_next_thread = thrd;
+        }
+        else {
+            struct stacklet_thread_s *next = g_all_threads->g_next_thread;
+            thrd->g_prev_thread = g_all_threads;
+            thrd->g_next_thread = next;
+            g_all_threads->g_next_thread = thrd;
+            next->g_prev_thread = thrd;
+        }
     }
     return thrd;
 }
 
 void stacklet_deletethread(stacklet_thread_handle thrd)
 {
+    /* remove 'thrd' from the circular doubly-linked list */
+    stacklet_thread_handle prev = thrd->g_prev_thread;
+    stacklet_thread_handle next = thrd->g_next_thread;
+    assert(next->g_prev_thread == thrd);
+    assert(prev->g_next_thread == thrd);
+    next->g_prev_thread = prev;
+    prev->g_next_thread = next;
+    assert(g_all_threads != NULL);
+    if (g_all_threads == thrd) {
+        g_all_threads = (next == thrd) ? NULL : next;
+    }
+    /* free it */
     free(thrd);
 }
 
             *pp = target->stack_prev;
             break;
         }
-    assert(target->id->stacklet == target);
+    /*assert(target->id->stacklet == target);
     if (target->id != &thrd->g_main_id)
-        free(target->id);
+    free(target->id);*/
     free(target);
 }
 
   }
   return ptr;
 }
+
+long _stacklet_capture_stack_pointer(stacklet_thread_handle thrd,
+                                     char **stackptr)
+{
+    if (thrd->g_stack_chain_head == NULL) {
+        /* running in 'main' */
+        return (long)stackptr;
+    }
+    else {
+        fprintf(stderr, "1!\n");
+        abort();
+    }
+}
+
+char **_stacklet_get_captured_pointer(long captured)
+{
+    if ((captured & 1) == 0) {
+        return (char**)captured;
+    }
+    else {
+        fprintf(stderr, "2!\n");
+        abort();
+    }
+}
+
+stacklet_handle _stacklet_get_captured_context(long captured)
+{
+    if ((captured & 1) == 0) {
+        /* it is one of the 'main' stacklets.  If it was moved away,
+           we need to figure out which one it was. */
+        char *p = (char *)captured;
+        struct stacklet_thread_s *thrd = g_all_threads;
+        if (thrd == NULL)
+            return NULL;   /* no stacklet_thread at all */
+
+        while (1) {
+            struct stacklet_s *stacklet = thrd->g_stack_chain_head;
+            if (stacklet != NULL) {
+                /* not running 'main'.  Find the main stacklet */
+                while (stacklet->stack_prev)
+                    stacklet = stacklet->stack_prev;
+
+                /* is 'captured' among the moved-away data? */
+                if (stacklet->stack_start <= p && p < stacklet->stack_stop) {
+                    /* yes.  to optimize the next calls make g_all_threads
+                       point directly to thrd. */
+                    g_all_threads = thrd;
+                    return stacklet;
+                }
+            }
+            thrd = thrd->g_next_thread;
+            if (thrd == g_all_threads)
+                break;
+        }
+        return NULL;
+    }
+    else {
+        fprintf(stderr, "3!\n");
+        abort();
+    }
+}

pypy/translator/c/src/stacklet/stacklet.h

  * the main stacklet.  This guarantees that it is possible to use
  * '_stacklet_get_...()' on a regular address taken before starting
  * to use stacklets.
+ *
+ * XXX assumes a single stacklet_thread_handle per thread
+ *
+ * XXX _stacklet_capture_stack_pointer() invalidates all 'long' values
+ * previously returned for the same stacklet that were for addresses
+ * later in the stack (i.e. lower).
  */
-long _stacklet_capture_stack_pointer(char **stackptr);
+long _stacklet_capture_stack_pointer(stacklet_thread_handle, char **stackptr);
 char **_stacklet_get_captured_pointer(long captured);
 stacklet_handle _stacklet_get_captured_context(long captured);
 

pypy/translator/c/src/stacklet/tests.c

 /************************************************************/
 
 struct test_captr_s {
-    long c, c1, c2;
+    long c, c0, c1, c2;
     char **fooref;
+    char **fooref0;
     char **fooref1;
     char **fooref2;
     stacklet_handle hmain;
     stacklet_handle h2;
 } tid;
 
-void cap_check_all(int depth);
+int cap_check_all(int depth);
 
 stacklet_handle stacklet_captr_callback_1(stacklet_handle h, void *arg)
 {
     status = 1;
 
     assert(_stacklet_get_captured_pointer(tid.c) == tid.fooref);
-    assert(_stacklet_get_captured_context(tid.c) == tid.hmain);
+    assert(_stacklet_get_captured_context(tid.c) == NULL);
     assert(*_stacklet_translate_pointer(tid.hmain, tid.fooref) == (char*)-42);
 
     char *ref1 = (char*)1111;
-    tid.c1 = _stacklet_capture_stack_pointer(&ref1);
+    tid.c1 = _stacklet_capture_stack_pointer(thrd, &ref1);
     tid.fooref1 = &ref1;
     assert(_stacklet_get_captured_pointer(tid.c1) == &ref1);
     assert(_stacklet_get_captured_context(tid.c1) == NULL);
     status = 2;
 
     char *ref2 = (char*)2222;
-    tid.c2 = _stacklet_capture_stack_pointer(&ref2);
+    tid.c2 = _stacklet_capture_stack_pointer(thrd, &ref2);
     tid.fooref2 = &ref2;
     assert(_stacklet_get_captured_pointer(tid.c2) == &ref2);
     assert(_stacklet_get_captured_context(tid.c2) == NULL);
 
-    cap_check_all(20);
-
     h = stacklet_switch(thrd, h);
     tid.hmain = h;
     tid.h2 = NULL;
     return stacklet_switch(thrd, h);
 }
 
-void cap_check_all(int depth)
+int cap_check_all(int depth)
 {
     assert(_stacklet_get_captured_pointer(tid.c) == tid.fooref);
+    /* we always get NULL because it's before the portion of the stack
+       that is copied away and restored: */
+    assert(_stacklet_get_captured_context(tid.c) == NULL);
+    assert(*_stacklet_translate_pointer(tid.hmain, tid.fooref) == (char*)-42);
+
+    assert(_stacklet_get_captured_pointer(tid.c0) == tid.fooref0);
     assert(_stacklet_get_captured_context(tid.c) == tid.hmain);
-    assert(*_stacklet_translate_pointer(tid.hmain, tid.fooref) == (char*)-42);
+    assert(*_stacklet_translate_pointer(tid.hmain, tid.fooref) == (char*)6363);
 
     assert(_stacklet_get_captured_pointer(tid.c1) == tid.fooref1);
     assert(_stacklet_get_captured_context(tid.c1) == tid.h1);
     assert(*_stacklet_translate_pointer(tid.h2, tid.fooref2) == (char*)2222);
 
     if (depth > 0)
-        cap_check_all(depth - 1);
-
-    assert(_stacklet_get_captured_pointer(tid.c) == tid.fooref);
-    assert(_stacklet_get_captured_context(tid.c) == tid.hmain);
-    assert(*_stacklet_translate_pointer(tid.hmain, tid.fooref) == (char*)-42);
-
-    assert(_stacklet_get_captured_pointer(tid.c1) == tid.fooref1);
-    assert(_stacklet_get_captured_context(tid.c1) == tid.h1);
-    assert(*_stacklet_translate_pointer(tid.h1, tid.fooref1) == (char*)1111);
-
-    assert(_stacklet_get_captured_pointer(tid.c2) == tid.fooref2);
-    assert(_stacklet_get_captured_context(tid.c2) == tid.h2);
-    assert(*_stacklet_translate_pointer(tid.h2, tid.fooref2) == (char*)2222);
+        return cap_check_all(depth - 1) * depth;
+    return 1;
 }
 
-void test_stacklet_capture(void)
+int cap_with_extra_stack(int depth)
 {
-    char *foo = (char*)-42;
-    tid.c = _stacklet_capture_stack_pointer(&foo);
-    tid.fooref = &foo;
-    assert(tid.c == (long)tid.fooref);
-    assert(_stacklet_get_captured_pointer(tid.c) == &foo);
-    assert(_stacklet_get_captured_context(tid.c) == NULL);
+    stacklet_handle h1, h2;
+    char *foo0 = (char*)6363;
 
-    status = 0;
-    stacklet_handle h1 = stacklet_new(thrd, stacklet_captr_callback_1, NULL);
-    stacklet_handle h2 = stacklet_new(thrd, stacklet_captr_callback_2, NULL);
-    tid.hmain = NULL;
-    tid.h1 = h1;
-    tid.h2 = h2;
+    if (depth > 0)
+        return cap_with_extra_stack(depth - 1) * depth;
+
+    tid.c0 = _stacklet_capture_stack_pointer(thrd, &foo0);
+    tid.fooref0 = &foo0;
+    assert(tid.c0 == (long)tid.fooref0);
+    assert(_stacklet_get_captured_pointer(tid.c0) == &foo0);
+    assert(_stacklet_get_captured_context(tid.c0) == NULL);
 
     cap_check_all(20);
-    assert(_stacklet_capture_stack_pointer(tid.fooref) == tid.c);
+    assert(_stacklet_capture_stack_pointer(thrd, tid.fooref) == tid.c);
 
     assert(status == 2);
     status = 3;
     tid.h2 = h2;
 
     cap_check_all(20);
+    return 1;
+}
+
+void test_stacklet_capture(void)
+{
+    char *foo = (char*)-42;
+    tid.c = _stacklet_capture_stack_pointer(thrd, &foo);
+    tid.fooref = &foo;
+    assert(tid.c == (long)tid.fooref);
+    assert(_stacklet_get_captured_pointer(tid.c) == &foo);
+    assert(_stacklet_get_captured_context(tid.c) == NULL);
+
+    status = 0;
+    stacklet_handle h1 = stacklet_new(thrd, stacklet_captr_callback_1, NULL);
+    stacklet_handle h2 = stacklet_new(thrd, stacklet_captr_callback_2, NULL);
+    tid.hmain = NULL;
+    tid.h1 = h1;
+    tid.h2 = h2;
+
+    cap_with_extra_stack(20);
 
     assert(status == 6);
-    h1 = stacklet_switch(thrd, h1);
+    h1 = stacklet_switch(thrd, tid.h1);
     assert(h1 == EMPTY_STACKLET_HANDLE);
-    h2 = stacklet_switch(thrd, h2);
+    h2 = stacklet_switch(thrd, tid.h2);
     assert(h2 == EMPTY_STACKLET_HANDLE);
 }