There is a project as your work. http://code.google.com/p/js-coroutine/

On Mar 2, 8:18 pm, ejpbruel <[email protected]> wrote:
> Hello,
>
> I am currently working on a proof of concept of using the stdlibc
> makecontext/swapcontext functions in conjunction with v8. I know that
> v8 is technically notthreadsafe, but since these functions allow the
> explicit creation and scheduling ofthreadcontexts, no race
> conditions should occur, so it is at least conceivable that this
> willwork.
>
> The control flow for the sample code below is as follows:
> - main() creates athreadcontext which will call a central dispatch
> loop (loop())
> - main() initializes v8 with three function callbacks on the global
> object (readAsync, read, and log)
> - main() compiles and runs the script in str (defined at the beginning
> of the script)
>
> - the evaluated script calls readAsync()
> - readAsync() calls push() with readAysnc_helper() as argument
> - push() creates a newthreadcontext which will call
> readAsync_helper()
> - push() and readAsync() both return
>
> - the evaluated script calls read()
> - read() calls read_helper() directly
> - read_helper() needs to do a blocking call on fd 0 (stdin), so it
> calls yield() with that fd as argument
> - yield() registers the current context as being blocked
> - yield() switches to the context for the central dispatch loop
>
> - loop() first handles any newly create contexts
> - the context for readAsync_helper() is newly created, so loop()
> switches to there
> - readAsync() also calls read_helper()
> - read_helper() needs to do a (potentially) blocking call on fd 3, so
> it calls yield() with that fd as argument
> - yield() registers the current context as being blocked
> - yield() switches to the context for the central dispatch loop
>
> - no more newly created contexts are available, so loop() now handles
> all blocking contexts
> - loop() performs a select to see which fd's become available for
> reading
> - fd 3 becomes available first, so loop() switches to
> readAsync_helper()
> - readAsync_helper() does a blocking read (which will not block
> because of the select)
> - readAsync_helper() calls a function object which was stored earlier
> (see readAsync())
>
> At this point, the callback does not seem to be called (if it were,
> this should have resulted in a call to log()). Instead, V8 complains
> to me:
> Uncaught RangeError: Maximum call stack size exceeded
>
> The cause of this error is unclear to me, but I'm suspecting that it
> is related to the fact that eachthreadcontext has a completely
> separate stack (which I explicitly allocate using malloc()), and this
> somehow confuses V8. What I need to know is why V8 gets confused over
> this, and more importantly, what I need to do in order to be able to
> do a callback to Javascript/call on a function object from a 
> differentthreadcontext than the one on which I initialized v8.
>
> As a sidenote, if I do *not* call the function object, the program
> proceeds as expected. readAsync_helper() returns to the dispatch loop,
> which will subsequently unblock and switch to read_helper() when the
> user types something in the terminal (so that fd 0 becomes ready for
> reading).
>
> Last but not least, here's the example code I used (note that a file
> named test must be available in the same directory in order for it to
> run correctly!):
>
> #include <ucontext.h>
> #include <stdlib.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <stdio.h>
> #include <sys/select.h>
> #include <v8-debug.h>
>
> using namespace v8;
>
> #define SIZE 1024
>
> const char str[] = "readAsync(function () { log('async ok') });"
>                    "read(); log('sync ok');";
>
> ucontext_t uc; // Dispatch loop context
> int nacs;
> ucontext_t acs[10]; // Newly created contexts
> int nfds;
> fd_set fds;
> ucontext_t ucs[10]; // Currently blocked context
> Persistent<Context> context;
> Persistent<Function> function;
>
> Handle<Value> log(const Arguments& args)
> {
>     String::Utf8Value value(args[0]);
>
>     printf("%s\n", *value);
>
> }
>
> void yield(int fd)
> {
>     if (nfds < fd + 1)
>         nfds = fd + 1;
>     FD_SET(fd, &fds);
>     swapcontext(&ucs[fd], &uc);
>     FD_CLR(fd, &fds);
>     do
>         --fd;
>     while (fd >= 0 && !FD_ISSET(fd, &fds));
>     if (nfds > fd + 1)
>         nfds = fd + 1;
>
> }
>
> void read_helper(int fd)
> {
>     char data[SIZE];
>     size_t size;
>
>     yield(fd);
>     size = ::read(fd, data, SIZE);
>     fwrite(data, size, 1, stdout);
>
> }
>
> Handle<Value> read(const Arguments& args)
> {
>     read_helper(0);
>     return Undefined();
>
> }
>
> void readAsync_helper()
> {
>     int fd = open("test", O_RDONLY);
>
>     read_helper(fd);
>     function->Call(function, 0, 0);
>
> }
>
> void push(void (*func)(void))
> {
>     ucontext_t *ucp = &acs[nacs++];
>
>     getcontext(ucp);
>   ucp->uc_link = &uc;
>     ucp->uc_stack.ss_sp = malloc(SIGSTKSZ);
>     ucp->uc_stack.ss_size = SIGSTKSZ;
>     makecontext(ucp, func, 0);
>
> }
>
> Handle<Value> readAsync(const Arguments& args)
> {
>     function =
> Persistent<Function>::New(Handle<Function>::Cast(args[0]));
>
>     push(readAsync_helper);
>     return Undefined();
>
> }
>
> void loop()
> {
>     fd_set readfds;
>     int n, i;
>
>     for (;;) {
>         while (nacs > 0)
>             swapcontext(&uc, &acs[--nacs]);
>         readfds = fds;
>         n = select(nfds, &readfds, 0, 0, 0);
>         i = 0;
>         while (n--) {
>             while (!FD_ISSET(i, &readfds))
>                 ++i;
>             swapcontext(&uc, &ucs[i]);
>         }
>     }
>
> }
>
> int main(int argc, char** argv)
> {
>     HandleScope scope;
>     Handle<ObjectTemplate> global;
>
>     getcontext(&uc);
>     uc.uc_link = NULL;
>     uc.uc_stack.ss_sp = malloc(SIGSTKSZ);
>     uc.uc_stack.ss_size = SIGSTKSZ;
>     makecontext(&uc, (void (*)(void)) loop, 0);
>     global = ObjectTemplate::New();
>     global->Set(String::New("readAsync"),
> FunctionTemplate::New(readAsync));
>     global->Set(String::New("read"), FunctionTemplate::New(read));
>     global->Set(String::New("log"), FunctionTemplate::New(log));
>     context = Context::New(0, global);
>     {
>         Context::Scope scope(context);
>         Handle<String> source = String::New(str);
>         Handle<Script> script = Script::Compile(source);
>
>         script->Run();
>     }
>     context.Dispose();
>     return 0;
>
>
>
> }

-- 
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users

Reply via email to