From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Ian Price Newsgroups: gmane.lisp.guile.user Subject: Re: guile and coroutines controlled from C Date: Mon, 30 Jul 2012 05:56:43 +0100 Message-ID: <877gtlvoc4.fsf@Kagami.home> References: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: dough.gmane.org 1343624223 8522 80.91.229.3 (30 Jul 2012 04:57:03 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Mon, 30 Jul 2012 04:57:03 +0000 (UTC) Cc: guile-user@gnu.org To: Vincent Bernat Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Mon Jul 30 06:57:01 2012 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Svi2N-0005Cn-9d for guile-user@m.gmane.org; Mon, 30 Jul 2012 06:56:59 +0200 Original-Received: from localhost ([::1]:46138 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Svi2M-0008Fa-If for guile-user@m.gmane.org; Mon, 30 Jul 2012 00:56:58 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:40352) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Svi2H-0008FR-PI for guile-user@gnu.org; Mon, 30 Jul 2012 00:56:54 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Svi2G-0006pU-70 for guile-user@gnu.org; Mon, 30 Jul 2012 00:56:53 -0400 Original-Received: from mail-wi0-f171.google.com ([209.85.212.171]:41258) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Svi2F-0006oa-SX for guile-user@gnu.org; Mon, 30 Jul 2012 00:56:52 -0400 Original-Received: by wibhq4 with SMTP id hq4so1114505wib.12 for ; Sun, 29 Jul 2012 21:56:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version:content-type; bh=t1ZQFfas+DpaH7bBko8LrPbjX7mgZj9Kq9WFURnytdQ=; b=bdKDu38La4X15U1aM8KBlm8oqq1bUFfWHFx6FAAb095crKmubocvY9TJCgHxeW4xUb vArwq2POH6MMXMU/fkmBd8AWfxCj+0lVCR4ChVK17c/MdkKxmvep2hrl5FQc85TkfI3P Xpxx3gEMfHczFbq4ByOpIm5RHWkXz+UwBy6EbtgOFSceMassuou2T9Dpcw4mTA/MtuBR bwCdrmlhI3lkI7Q/9Mg0dXILxCxH8X2uVXy+c1AANMCrLcimlorT6D0w+lrmWnRhFMxP ctM9FW7ZQRAqIZjcXJ3QcuGJsnDz3dJDdxpt1/MfVAyNNmFhJazL3jrP+N7sBYYW9R6Q oBPQ== Original-Received: by 10.180.84.1 with SMTP id u1mr23449740wiy.15.1343624210330; Sun, 29 Jul 2012 21:56:50 -0700 (PDT) Original-Received: from Kagami.home (host86-177-154-236.range86-177.btcentralplus.com. [86.177.154.236]) by mx.google.com with ESMTPS id q4sm14521861wix.9.2012.07.29.21.56.47 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 29 Jul 2012 21:56:49 -0700 (PDT) In-Reply-To: (Vincent Bernat's message of "Sat, 28 Jul 2012 19:29:26 +0200") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.212.171 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: guile-user-bounces+guile-user=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.user:9537 Archived-At: Vincent Bernat writes: > Hi! > I would like to add Guile scripting to an actual program to allow a user > to write simple network-related scenarios. Those scenarios will be run > in parallel on several entities. The application is event-driven and I > want to hide this fact to the user. She should be able to write a > scenario in a simple blocking style: Hi, always happy to new uses for guile. > > #v+ > (let ((v1 (do-something-blocking "arg1" "arg2")) > (v2 (do-something-blocking "arg3" "arg4"))) > (when (< (+ v1 v2) 10) (...))) > #v- > > `do-something-blocking` is a registered function written in C. I want to > be able to pause the execution inside this function and then resume it > later (when I my program got the data wanted by the user). In the > meantime, another "cooperative thread" may be executed. > > In Lua, this is something that can be done with coroutines which can be > yield and resumed from C. In Guile, there are continuations but I have > hard time to understand how this should work from C. > > What would be the equivalent of this in Guile? > http://kristianrumberg.wordpress.com/2010/11/21/135/ So, is it a C function you want to pause and resume, or a scheme one? Your first statement implies the former, but that example you pointed to implies you want scheme coroutines, that are callable from C. Both should be possible, but I'd need to do some experimentation before providing help with the former, as I'm not entirely sure about the interaction C and continuations in the vm. As for scheme coroutines, I think Wingo does that in one of the asynchronous IO branches, but I'm not sure if it exported for general use. A quick hack, I wrote is posted below. Threads are represented by thunks and are ran by calling said thunk. They would be called from C in the same way as any other function. In practice, it would be cleaner to create a new record type for these. (use-modules (ice-9 q)) ;; yech, but it'll do (define (list->q l) (define q (make-q)) (for-each (lambda (x) (enq! q x)) l) q) (define (run threads) ;; simple round robin scheduler (define *q* (list->q threads)) (while (not (q-empty? *q*)) (let ((thread (deq! *q*))) (when (eq? 'not-done (thread)) (enq! *q* thread))))) (define (make-thread thread) ;; NB. this might be cleaner with delimited continuations, but they ;; seem to scare people even more than continuations for some reason... ;; A thread is a thunk, that performs some computation, then returns ;; either 'not-done or 'done (lambda () (call-with-current-continuation (lambda (start) ;; capture "the stack" before routines is ran (thread (lambda () (call-with-current-continuation (lambda (current) ;; save current "stack" for thread ;; so that we continue from there next time (set! thread current) ;; then we need to cleanup, and go back to where ;; we were before the thread began executing (start 'not-done))))) ;; should probably mutate thread one last time, so that further ;; calls always just return 'done 'done)))) (define thread1 (make-thread (lambda (yield) (let loop ((i 3)) (if (zero? i) 'done (begin (display "in thread 1...\n") (yield) (loop (- i 1)))))))) (define thread2 (make-thread (lambda (yield) (let loop ((i 5)) (if (zero? i) 'done (begin (display "in thread 2...\n") (yield) (loop (- i 1)))))))) (define thread3 (make-thread (lambda (yield) (let loop ((i 4)) (if (zero? i) 'done (begin (display "in thread 3...\n") (yield) (loop (- i 1)))))))) (run (list thread1 thread2 thread3)) ;; Strangely enough, I was able to write this out and have it work first ;; time, which is a first for me writing continuation code :P ~ $ guile -s /tmp/contexample.scm in thread 1... in thread 2... in thread 3... in thread 1... in thread 2... in thread 3... in thread 1... in thread 2... in thread 3... in thread 2... in thread 3... in thread 2... ~ $ I hope that gives you a head start. If I've confused you more, I can only apologise. If you aren't familiar with continuations at all, you could try reading http://tmp.barzilay.org/cont.txt -- Ian Price "Programming is like pinball. The reward for doing it well is the opportunity to do it again" - from "The Wizardy Compiled"