unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Some introductory docs about C level threading
@ 2005-01-21 18:29 Marius Vollmer
  2005-01-21 21:20 ` Neil Jerram
                   ` (4 more replies)
  0 siblings, 5 replies; 35+ messages in thread
From: Marius Vollmer @ 2005-01-21 18:29 UTC (permalink / raw)


Hi,

this describes the model for C level threading for Guile 1.8.  What do
you think?

4.3.4 Asynchronous Signals
--------------------------

You can not call libguile functions from handlers for POSIX signals, but
you can register Scheme handlers for POSIX signals such as `SIGINT'.
These handlers do not run during the actual signal delivery.  Instead,
they are run when the program (more precisely, the thread that the
handler has been registered for) reaches the next _safe point_.

   The libguile functions themselves have many such safe points.
Consequently, you must be prepared for arbitrary actions anytime you
call a libguile function.  For example, even `scm_cons' can contain a
safe point and when a signal handler is pending for your thread,
calling `scm_cons' will run this handler and anything might happen,
including a non-local exit although `scm_cons' would not ordinarily do
such a thing on its own.

   If you do not want to allow the running of asynchronous signal
handlers, you can block them temporarily with `scm_frame_block_asyncs',
for example.  See *Note System asyncs::.

   Since signal handling in Guile relies on safe points, you need to
make sure that your functions do offer enough of them.  Normally,
calling libguile functions in the normal course of action is all that
is needed.  But when a thread might spent a long time in a code section
that calls no libguile function, it is good to include explicit safe
points.  This can allow the user to interrupt your code with <C-c>, for
example.

   You can do this with the macro `SCM_TICK'.  This macro is
syntactically a statement.  That is, you could use it like this:

     while (1)
       {
         SCM_TICK;
         do_some_work ();
       }

   Frequent execution of a safe point is even more important in multi
threaded programs, *Note Multi-Threading::.


4.3.5 Multi-Threading
---------------------

Guile can be used in multi-threaded programs just as well as in
single-threaded ones.

   Each thread that wants to use functions from libguile must put itself
into _guile mode_ and must then follow a few rules.  If it doesn't want
to honer these rules in certain situations, a thread can temporarily
leave guile mode (but can no longer use libguile functions during that
time, of course).

   Threads enter guile mode by calling `scm_with_guile',
`scm_boot_guile', or `scm_init_guile'.  As explained in the reference
documentation for these functions, Guile will then learn about the
stack bounds of the thread and can protect the `SCM' values that are
stored in local variables.  When a thread puts itself into guile mode
for the first time, it gets a Scheme representation and is listed by
`all-threads', for example.

   While in guile mode, a thread promises to reach a safe point
reasonably frequently (*note Asynchronous Signals::).  In addition to
running signal handlers, these points are also potential rendezvous
points of all guile mode threads where Guile can orchestrate global
things like garbage collection.  Consequently, when a thread in guile
mode blocks and does no longer frequent safe points, it might cause all
other guile mode threads to block as well.  To prevent this from
happening, a guile mode thread should either only block in libguile
functions (who know how to do it right), or should temporarily leave
guile mode with `scm_without_guile' or
`scm_leave_guile'/`scm_enter_guile'.

   For some comming blocking operations, Guile provides convenience
functions.  For example, if you want to lock a pthread mutex while in
guile mode, you might want to use `scm_pthread_mutex_lock' which is
just like `pthread_mutex_lock' except that it leaves guile mode while
blocking.

   All libguile functions are (intended to be) robust in the face of
multiple threads using them concurrently.  This means that there is no
risk of the internal data structures of libguile becoming corrupted in
such a way that the process crashes.

   A program might still produce non-sensical results, though.  Taking
hash tables as an example, Guile guarantees that you can use them from
multiple threads concurrently and a hashtable will always remain a valid
hashtable and Guile will not crash when you access it.  It does not
guarantee, however, that inserting into it concurrently from two threads
will give useful results: only one insertion might actually happen, none
might happen, or the table might in general be modified in a totally
arbitrary manner.  (It will still be a valid hashtable, but not the one
that you might have expected.)

   Thus, you need to put in additional synchronizations when multiple
threads want to use a single hashtable, or any other mutable Scheme
object.

   When writing C code for use with libguile, you should try to make it
robust as well.  An example that converts a list into a vector will help
to illustrate.  Here is a correct version:

     SCM
     my_list_to_vector (SCM list)
     {
       SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
       size_t len, i;

       len = SCM_SIMPLE_VECTOR_LENGTH (vector);
       i = 0;
       while (i < len && scm_is_pair (list))
         {
           SCM_SIMPLE_VECTOR_SET (vector, i, SCM_CAR (list));
           list = SCM_CDR (list);
           i++;
         }

       return vector;
     }

   The first thing to note is that storing into a `SCM' location
concurrently from multiple threads is guaranteed to be robust: you don't
know which value wins but it will in any case be a valid `SCM' value.

   But there is no guarantee that the list referenced by LIST is not
modified in another thread while the loop iterates over it.  Thus, while
copying its elements into the vector, the list might get longer or
shorter.  For this reason, the loop must check both that it doesn't
overrun the vector (`SCM_SIMPLE_VECTOR_SET' does no range-checking) and
that it doesn't overrung the list (`SCM_CAR' and `SCM_CDR' likewise do
no type checking).

   It is safe to use `SCM_CAR' and `SCM_CDR' on the local variable LIST
once it is known that the variable contains a pair.  The contents of
the pair might change spontaneously, but it will always stay a valid
pair (and a local variable will of course not spontaneously point to a
different Scheme object).

   Likewise, a simple vector such as the one returned by
`scm_make_vector' is guaranteed to always stay the same length so that
it is safe to only use SCM_SIMPLE_VECTOR_LENGTH once and store the
result.  (In the example, VECTOR is safe anyway since it is a fresh
object that no other thread can possibly know about until it is
returned from `my_list_to_vector'.)

   Of course the behavior of `my_list_to_vector' is suboptimal when
LIST does indeed gets asynchronously lengthened or shortened in another
thread.  But it is robust: it will always return a valid vector.  That
vector might be shorter than expected, or its last elements might be
unspecified, but it is a valid vector and if a program wants to rule
out these cases, it must avoid modifiying the list asynchronously.

   Here is another version that is also correct:

     SCM
     my_pedantic_list_to_vector (SCM list)
     {
       SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
       size_t len, i;

       len = SCM_SIMPLE_VECTOR_LENGTH (vector);
       i = 0;
       while (i < len)
         {
           SCM_SIMPLE_VECTOR_SET (vector, i, scm_car (list));
           list = scm_cdr (list);
           i++;
         }

       return vector;
     }

   This version uses the type-checking and thread-robust functions
`scm_car' and `scm_cdr' instead of the faster, but less robust macros
`SCM_CAR' and `SCM_CDR'.  When the list is shortened (that is, when
LIST holds a non-pair), `scm_car' will throw an error.  This might be
preferable to just returning a half-initialized vector.



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-21 18:29 Some introductory docs about C level threading Marius Vollmer
@ 2005-01-21 21:20 ` Neil Jerram
  2005-01-24 19:23   ` Marius Vollmer
  2005-01-22 12:37 ` tomas
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: Neil Jerram @ 2005-01-21 21:20 UTC (permalink / raw)
  Cc: guile-user

Marius Vollmer wrote:
> Hi,
> 
> this describes the model for C level threading for Guile 1.8.  What do
> you think?

Looks very nice to me!  I just spotted one spelling mistake: your 
"honer" should be "honour" (or perhaps "honor" - are the Guile docs 
supposed to be British English or American English?).

	Neil


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-21 18:29 Some introductory docs about C level threading Marius Vollmer
  2005-01-21 21:20 ` Neil Jerram
@ 2005-01-22 12:37 ` tomas
  2005-01-24 19:28   ` Marius Vollmer
  2005-01-23 23:34 ` Kevin Ryde
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 35+ messages in thread
From: tomas @ 2005-01-22 12:37 UTC (permalink / raw)
  Cc: guile-user


[-- Attachment #1.1: Type: text/plain, Size: 857 bytes --]

On Fri, Jan 21, 2005 at 07:29:35PM +0100, Marius Vollmer wrote:
> Hi,
> 
> this describes the model for C level threading for Guile 1.8.  What do
> you think?

Great! Random typo:

[...]

> 4.3.5 Multi-Threading
> ---------------------
[...]
> 
>    For some comming blocking operations, Guile provides convenience
              ^^^^^^^
coming? common? (I guess second)

Thanks for your great work.

I'm not much into Guile these days, so sorry if I'm
asking the obvious: is there a function to defer
something to a safe point? (like I'm `outside Guile',
say in a signal handler and want to do some things
there and leave others for when I'm at a safe point
and say scm_execute_at_safe_point(closure).

The implementation itself has to have this, of course.
Can it be made available in the API? Is already?

Regards
-- tomas

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 140 bytes --]

_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-21 18:29 Some introductory docs about C level threading Marius Vollmer
  2005-01-21 21:20 ` Neil Jerram
  2005-01-22 12:37 ` tomas
@ 2005-01-23 23:34 ` Kevin Ryde
  2005-01-24 19:31 ` Some new reference docs about initialization Marius Vollmer
  2005-02-01 17:37 ` Some introductory docs about C level threading Ken Raeburn
  4 siblings, 0 replies; 35+ messages in thread
From: Kevin Ryde @ 2005-01-23 23:34 UTC (permalink / raw)
  Cc: guile-user

Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>
>    The libguile functions themselves have many such safe points.
> Consequently, you must be prepared for arbitrary actions anytime you
> call a libguile function.

I'd like to see a few explicitly run signals.  Eg. scm_raise so the
handler (if any) gets run before scm_raise returns.  Or
write-string/partial, so a possible SIGPIPE handler is run before that
function returns.  (Perhaps everywhere doing a write().)

Basically if an scm func does something we know might raise a signal,
allow that to run before the func returns.

I suspect eval means handlers run before anything else happens in a
scheme program, usually, but it'd be nice if C code calling scm_'s got
the same effect.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-21 21:20 ` Neil Jerram
@ 2005-01-24 19:23   ` Marius Vollmer
  2005-02-15  4:11     ` Robert Uhl
  0 siblings, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-01-24 19:23 UTC (permalink / raw)
  Cc: guile-user

Neil Jerram <neil@ossau.uklinux.net> writes:

> I just spotted one spelling mistake: your "honer" should be "honour"
> (or perhaps "honor" - are the Guile docs supposed to be British
> English or American English?).

Hmm, I can't say.  The canonical English of computer stuff is probably
American English...


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-22 12:37 ` tomas
@ 2005-01-24 19:28   ` Marius Vollmer
  2005-01-25  9:06     ` tomas
  0 siblings, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-01-24 19:28 UTC (permalink / raw)
  Cc: guile-user

tomas@fabula.de writes:

>>    For some comming blocking operations, Guile provides convenience
>               ^^^^^^^
> coming? common? (I guess second)

'Common', thanks!

> I'm not much into Guile these days, so sorry if I'm asking the
> obvious: is there a function to defer something to a safe point?
> (like I'm `outside Guile', say in a signal handler and want to do
> some things there and leave others for when I'm at a safe point and
> say scm_execute_at_safe_point(closure).

Right now, you can only queue asynchronous execution from within
Guile, but we should probably offer a way to do this from outside
Guile.  The problem is that outside of Guile, you can not deal with
SCM values at all, so we would have to package up an opaque object
that contains all information while in guile mode, which could then be
triggered from outside of guile.

> The implementation itself has to have this, of course.

Yes, via some magic.  Might be worth it to package up this magic as
outlines above.

Anyone? :-)


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Some new reference docs about initialization
  2005-01-21 18:29 Some introductory docs about C level threading Marius Vollmer
                   ` (2 preceding siblings ...)
  2005-01-23 23:34 ` Kevin Ryde
@ 2005-01-24 19:31 ` Marius Vollmer
  2005-01-24 20:27   ` Andreas Rottmann
  2005-02-01 17:37 ` Some introductory docs about C level threading Ken Raeburn
  4 siblings, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-01-24 19:31 UTC (permalink / raw)


What do you think?

5.3 Initializing Guile
======================

Each thread that wants to use function from the Guile API needs to put
itself into guile mode with either `scm_with_guile' or
`scm_init_guile'.  The global state of Guile is initialized
automatically when the first thread enters guile mode.

   When a thread wants to block outside of a Guile API function, it
should leave guile mode temporarily with either `scm_without_guile' or
`scm_leave_guile', *Note Threads::.

 -- C Function: void *scm_with_guile (void *(*func)(void *), void *data)
     Call FUNC, passing it DATA and return what FUNC returns.  While
     FUNC is running, the current thread is in guile mode and can thus
     use the Guile API.

     When `scm_with_guile' is called from guile mode, the thread remains
     in guile mode when `scm_with_guile' returns.

     Otherwise, it puts the current thread into guile mode and, if
     needed, gives it a Scheme representation that is contained in the
     list returned by `all-threads', for example.  This Scheme
     representation is not removed when `scm_with_guile' returns so
     that a given thread is always represented by the same Scheme value
     during its lifetime, if at all.

     When this is the first thread that enters guile mode, the global
     state of Guile is initialized before calling `func'.

     When a throw happens while FUNC runs (such as a signalled error)
     that is not caught, a short message is printed to the current
     error port and `scm_with_guile' returns `NULL'.  When a
     continuation is invoked that would make the control flow cross
     this call to `scm_with_guile', an error will be signalled at the
     point of continuation invokation.  Thus, `scm_with_guile'
     guaranteed to return exactly once.

     When `scm_with_guile' returns, the thread is no longer in guile
     mode (except when `scm_with_guile' was called from guile mode, see
     above).  Thus, only `func' can store `SCM' variables on the stack
     and be sure that they are protected from the garbage collector.
     See `scm_init_guile' for another approach at initializing Guile
     that does not have this restriction.

     It is OK to call `scm_with_guile' while a thread has temporarily
     left guile mode via `scm_without_guile' or `scm_leave_guile'.  It
     will then simply temporarily enter guile mode again.

 -- C Function: void scm_init_guile ()
     Arrange things so as if all of the code of the current thread
     would be executed from within a call to `scm_with_guile'.  That
     is, all functions called by the current thread can assume that
     `SCM' values on their stack frames are protected from the garbage
     collector (except when the thread has explicitely left guile mode,
     of course).

     When `scm_init_guile' is called from a thread that already has been
     in guile mode once, nothing happens.  This behavior matters when
     you call `scm_init_guile' while the thread has only temporarily
     left guile mode: in that case the thread will not be in guile mode
     after `scm_init_guile' returns.  Thus, you should not use
     `scm_init_guile' in such a scenario.

     When a uncaught throw happens in a thread that has been put into
     guile mode via `scm_init_guile', a short message is printed to the
     current error port and the thread is exited via `scm_pthread_exit
     (NULL)'.  No restrictions are placed on continuations.

     The function `scm_init_guile' might not be available on all
     platforms since it requires some stack-bounds-finding magic that
     might not have been to all platforms that Guile runs on.  Thus, if
     you can, it is better to use `scm_with_guile' or its variation
     `scm_boot_guile' instead of this function.

 -- C Function: void scm_boot_guile (int ARGC, char **ARGV, void
          (*MAIN_FUNC) (void *DATA, int ARGC, char **ARGV), void *DATA)
     Enter guile mode as with `scm_with_guile' and call MAIN_FUNC,
     passing it DATA, ARGC, and ARGV as indicated.  When MAIN_FUNC
     returns, `scm_boot_guile' calls `exit (0)'; `scm_boot_guile' never
     returns.  If you want some other exit value, have MAIN_FUNC call
     `exit' itself.  If you don't want to exit at all, use
     `scm_with_guile' instead of `scm_boot_guile'.

     The function `scm_boot_guile' arranges for the Scheme
     `command-line' function to return the strings given by ARGC and
     ARGV.  If MAIN_FUNC modifies ARGC or ARGV, it should call
     `scm_set_program_arguments' with the final list, so Scheme code
     will know which arguments have been processed.

 -- C Function: void scm_shell (int ARGC, char **ARGV)
     Process command-line arguments in the manner of the `guile'
     executable.  This includes loading the normal Guile initialization
     files, interacting with the user or running any scripts or
     expressions specified by `-s' or `-e' options, and then exiting.
     *Note Invoking Guile::, for more details.

     Since this function does not return, you must do all
     application-specific initialization before calling this function.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some new reference docs about initialization
  2005-01-24 19:31 ` Some new reference docs about initialization Marius Vollmer
@ 2005-01-24 20:27   ` Andreas Rottmann
  2005-01-24 22:00     ` Marius Vollmer
  0 siblings, 1 reply; 35+ messages in thread
From: Andreas Rottmann @ 2005-01-24 20:27 UTC (permalink / raw)


Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:

>      The function `scm_init_guile' might not be available on all
>      platforms since it requires some stack-bounds-finding magic that
>      might not have been to all platforms that Guile runs on.  Thus, if
                          ^
                          ported?

Rotty
-- 
Andreas Rottmann         | Rotty@ICQ      | 118634484@ICQ | a.rottmann@gmx.at
http://yi.org/rotty      | GnuPG Key: http://yi.org/rotty/gpg.asc
Fingerprint              | DFB4 4EB4 78A4 5EEE 6219  F228 F92F CFC5 01FD 5B62

Any technology not indistinguishable from magic is insufficiently advanced.
   -- Terry Pratchett



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some new reference docs about initialization
  2005-01-24 20:27   ` Andreas Rottmann
@ 2005-01-24 22:00     ` Marius Vollmer
  0 siblings, 0 replies; 35+ messages in thread
From: Marius Vollmer @ 2005-01-24 22:00 UTC (permalink / raw)
  Cc: guile-user

Andreas Rottmann <a.rottmann@gmx.at> writes:

> Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>
>>      The function `scm_init_guile' might not be available on all
>>      platforms since it requires some stack-bounds-finding magic that
>>      might not have been to all platforms that Guile runs on.  Thus, if
>                           ^
>                           ported?

Yes!  Nothing more seriously wrong with this? ;-)


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-24 19:28   ` Marius Vollmer
@ 2005-01-25  9:06     ` tomas
  2005-01-25 15:58       ` Rob Browning
  0 siblings, 1 reply; 35+ messages in thread
From: tomas @ 2005-01-25  9:06 UTC (permalink / raw)
  Cc: guile-user


[-- Attachment #1.1: Type: text/plain, Size: 1196 bytes --]

On Mon, Jan 24, 2005 at 08:28:36PM +0100, Marius Vollmer wrote:
> tomas@fabula.de writes:

[...]

> > I'm not much into Guile these days [...]

> Right now, you can only queue asynchronous execution from within
> Guile, but we should probably offer a way to do this from outside
> Guile.  The problem [...]

Thanks, Marius, for taking notice of this one lurker ;-)

Yes, I imagine that this is the hard part. But it might be the
really useful one, epecially for non-Guile apps onto which a
Guile interpreter gets tacked. My standard examples are Apache
or the PostgreSQL server. Those have their own signal handlers
and so on. As a module writer you get just a hook (and there
you won't be in Guile mode). So if you want to write your handlers
in Guile, you'd need some way of saying `call this when it's
safe'.

> > The implementation itself has to have this, of course.
> 
> Yes, via some magic.  Might be worth it to package up this magic as
> outlines above.
> 
> Anyone? :-)

Brrr. It's a while since I had a look into Guile, and I'm short on
time these days, so it might take quite a while. I would'nt mind if
someone beats me to it ;-)

Regards
-- tomás

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 140 bytes --]

_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-25  9:06     ` tomas
@ 2005-01-25 15:58       ` Rob Browning
  2005-01-25 16:01         ` Rob Browning
  2005-01-26  9:05         ` tomas
  0 siblings, 2 replies; 35+ messages in thread
From: Rob Browning @ 2005-01-25 15:58 UTC (permalink / raw)
  Cc: guile-user, Marius Vollmer

tomas@fabula.de writes:

> Yes, I imagine that this is the hard part. But it might be the
> really useful one, epecially for non-Guile apps onto which a Guile
> interpreter gets tacked. My standard examples are Apache or the
> PostgreSQL server. Those have their own signal handlers and so
> on. As a module writer you get just a hook (and there you won't be
> in Guile mode). So if you want to write your handlers in Guile,
> you'd need some way of saying `call this when it's safe'.

Though it might be to slow, a simple alternative would be to just have
a guile thread watch a C data structure that the server signal handler
manipulates.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-25 15:58       ` Rob Browning
@ 2005-01-25 16:01         ` Rob Browning
  2005-01-26  9:05         ` tomas
  1 sibling, 0 replies; 35+ messages in thread
From: Rob Browning @ 2005-01-25 16:01 UTC (permalink / raw)
  Cc: guile-user, Marius Vollmer

Rob Browning <rlb@defaultvalue.org> writes:

> Though it might be to slow, a simple alternative would be to just have

Erm, "too slow".

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592  F9A0 25C8 D377 8C7E 73A4


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-25 15:58       ` Rob Browning
  2005-01-25 16:01         ` Rob Browning
@ 2005-01-26  9:05         ` tomas
  2005-02-01 16:01           ` Marius Vollmer
  1 sibling, 1 reply; 35+ messages in thread
From: tomas @ 2005-01-26  9:05 UTC (permalink / raw)
  Cc: guile-user, Marius Vollmer


[-- Attachment #1.1: Type: text/plain, Size: 963 bytes --]

On Tue, Jan 25, 2005 at 09:58:52AM -0600, Rob Browning wrote:
> tomas@fabula.de writes:
> 
[about putting a deferred call to Guile from a handler or similar]

> > Yes, I imagine that this is the hard part. But it might be the
> > really useful one, epecially for non-Guile apps onto which a Guile
> > interpreter gets tacked [...]

> Though it might be to slow, a simple alternative would be to just have
> a guile thread watch a C data structure that the server signal handler
> manipulates.

I'm not as much concerned about speed as I am about understandability
of the programmer interface. What you propose is a perfectly valid
implementation technique -- what I'm afraid of is that everyone ends
up with a (slightly different) half-correct solution.

My point was rather a `since the implementation is doing this anyway,
and this would be a clearly understandable and simple interface function,
why not provide it?'.

Regards
-- tomás

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 140 bytes --]

_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-26  9:05         ` tomas
@ 2005-02-01 16:01           ` Marius Vollmer
  2005-02-02  9:31             ` tomas
  0 siblings, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-02-01 16:01 UTC (permalink / raw)
  Cc: guile-user, Rob Browning

tomas@fabula.de writes:

> My point was rather a `since the implementation is doing this anyway,
> and this would be a clearly understandable and simple interface function,
> why not provide it?'.

Yep.  What about the following:

   - int scm_create_new_os_signal (void)

   Return an integer that can be used as the signal number with
   scm_sigaction and scm_queue_os_signal.

   - void scm_queue_os_signal (int signum)

   Notify Guile that the OS signal signum has occured.  Guile will run
   the signal handler for it at the next safe point, as prepared by
   scm_sigaction.

   SIGNUM can be a number from signals.h, like SIGINT, or it can be a
   number returned by scm_create_new_os_signal.

   The function scm_queue_os_signal is save to be called at any time,
   including from OS signal handlers.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-21 18:29 Some introductory docs about C level threading Marius Vollmer
                   ` (3 preceding siblings ...)
  2005-01-24 19:31 ` Some new reference docs about initialization Marius Vollmer
@ 2005-02-01 17:37 ` Ken Raeburn
  2005-02-01 23:40   ` Kevin Ryde
  2005-02-09 12:04   ` Marius Vollmer
  4 siblings, 2 replies; 35+ messages in thread
From: Ken Raeburn @ 2005-02-01 17:37 UTC (permalink / raw)


On Jan 21, 2005, at 13:29, Marius Vollmer wrote:
> 4.3.5 Multi-Threading
> ---------------------
>      SCM
>      my_list_to_vector (SCM list)
>      {
>        SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
>        size_t len, i;
>
>        len = SCM_SIMPLE_VECTOR_LENGTH (vector);
>        i = 0;
>        while (i < len && scm_is_pair (list))
>          {
>            SCM_SIMPLE_VECTOR_SET (vector, i, SCM_CAR (list));
>            list = SCM_CDR (list);
>            i++;
>          }
>
>        return vector;
>      }
>
>    It is safe to use `SCM_CAR' and `SCM_CDR' on the local variable LIST
> once it is known that the variable contains a pair.  The contents of
> the pair might change spontaneously, but it will always stay a valid
> pair (and a local variable will of course not spontaneously point to a
> different Scheme object).

But is it guaranteed that, without locking, SCM_CAR and SCM_CDR will 
always return the "before" or "after" values while another thread is 
modifying them, and not some corrupted intermediate form?  Given 
typical data alignment and access, and hardware memory management 
techniques, and the small size of a SCM value, I'm not aware of a 
situation where it would be at all likely to happen, but I'm also not 
aware of any guarantee that it won't.

Though, even without weird memory management issues, consider:
   SCM_SETCAR(x, SCM_I_MAKINUM(i >> 2))    i some external int var
  -> (....x)[0] = ((... i >> 2) << 2 + scm_tc2_int)
  -> copy i, masking off bottom two bits, into target location; then add 
in scm_tc2_int

If SCM_CAR(x) is read at just the wrong time, the tag bits might not be 
correct.

It may also be the case that if both the car and cdr of the pair (or 
indeed, any two separate locations) are modified in one thread and read 
in another, the memory accesses could be reordered (by the compiler, or 
even by the CPU these days) such that the read-back contents of the 
pair don't seem to match the "before" or "after" values or even the 
expected intermediate state where the first-listed modification has 
been done but the second has not.

If someone's got lots more experience with multithreaded systems and 
wants to say I'm wrong, great.  I've been thinking about this a bit 
lately, trying to make a pile of code thread-safe at work, but I'm 
mostly coming at it from a theoretical perspective.

Ken



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-01 17:37 ` Some introductory docs about C level threading Ken Raeburn
@ 2005-02-01 23:40   ` Kevin Ryde
  2005-02-02  0:38     ` Ken Raeburn
  2005-02-09 12:08     ` Marius Vollmer
  2005-02-09 12:04   ` Marius Vollmer
  1 sibling, 2 replies; 35+ messages in thread
From: Kevin Ryde @ 2005-02-01 23:40 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:
>
>  -> (....x)[0] = ((... i >> 2) << 2 + scm_tc2_int)
>  -> copy i, masking off bottom two bits, into target location; then add 
> in scm_tc2_int

Any sensible compiler should do the one store that's given, and the
SCM type will mean it's atomic.

You can force load/stores to be exactly as given using `volatile', but
as far as I can tell this particular example shouldn't need that.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-01 23:40   ` Kevin Ryde
@ 2005-02-02  0:38     ` Ken Raeburn
  2005-02-07  0:48       ` Kevin Ryde
  2005-02-09 12:13       ` Marius Vollmer
  2005-02-09 12:08     ` Marius Vollmer
  1 sibling, 2 replies; 35+ messages in thread
From: Ken Raeburn @ 2005-02-02  0:38 UTC (permalink / raw)


On Feb 1, 2005, at 18:40, Kevin Ryde wrote:
> Ken Raeburn <raeburn@raeburn.org> writes:
>>  -> (....x)[0] = ((... i >> 2) << 2 + scm_tc2_int)
>>  -> copy i, masking off bottom two bits, into target location; then 
>> add
>> in scm_tc2_int
>
> Any sensible compiler should do the one store that's given, and the

Not if you have an architecture where memory-to-memory arithmetic 
operations are cheap and registers are few.  By "copy i, masking" I 
didn't mean "copy to register, do the mask, then store", I meant 
something like "andl (r0),i,-4; addl (r0),2".

In fact, for one architecture I've got in mind, another two-instruction 
sequence, a simple memory-to-memory copy followed by overwriting just 
the low two bits, would also do the trick.  As it happens, that 
architecture isn't especially register-starved, but one could probably 
construct a function using a lot of temporaries and increase pressure 
on the register allocator such that it might still be worth avoiding 
the register temporary.  (Sorry, I've done a little compiler hacking in 
my time...)

> SCM type will mean it's atomic.

If use of the SCM type is assumed to be atomic in terms of CPU memory 
access and inter-CPU memory consistency, that's fine, but it should be 
documented as such -- and we should acknowledge that ports to 
architectures where that assumption does not hold may not be possible.

> You can force load/stores to be exactly as given using `volatile', but
> as far as I can tell this particular example shouldn't need that.

The problem is, if there are any case where it would be needed, then we 
need to use it everywhere there could be a potential problem.  
Depending on just how it works out, that could mean essentially 
declaring some of the scheme object types (like cons cells) as 
volatile, which would be poor for performance.

And volatile declarations may fix the possibility of storing incomplete 
values, but I don't think it would deal with the cross-thread memory 
access ordering issue.

Ken



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-01 16:01           ` Marius Vollmer
@ 2005-02-02  9:31             ` tomas
  2005-02-02 13:18               ` Marius Vollmer
  0 siblings, 1 reply; 35+ messages in thread
From: tomas @ 2005-02-02  9:31 UTC (permalink / raw)
  Cc: guile-user, Rob Browning, tomas


[-- Attachment #1.1: Type: text/plain, Size: 1050 bytes --]

On Tue, Feb 01, 2005 at 05:01:40PM +0100, Marius Vollmer wrote:
> tomas@fabula.de writes:
> 
> > My point was rather a `since the implementation is doing this anyway,
    [...]
> 
> Yep.  What about the following:
> 
>    - int scm_create_new_os_signal (void)
> 
>    Return an integer that can be used as the signal number with
>    scm_sigaction and scm_queue_os_signal.
> 
>    - void scm_queue_os_signal (int signum)
> 
>    Notify Guile that the OS signal signum has occured. [...]
>    the signal handler for it at the next safe point, as prepared by
>    scm_sigaction.
> 
>    SIGNUM can be a number from signals.h, like SIGINT, or it can be a
>    number returned by scm_create_new_os_signal.
> 
>    The function scm_queue_os_signal is save to be called at any time,
>    including from OS signal handlers.

Yes. I think this looks very nice. Some might argue for something more
abstract than an integer (a signal_t or whatnot) -- I wouldn't oppose,
but I'm very happy with what you propose.

Thanks
-- tomás

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 140 bytes --]

_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-02  9:31             ` tomas
@ 2005-02-02 13:18               ` Marius Vollmer
  2005-02-02 13:47                 ` tomas
  0 siblings, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-02-02 13:18 UTC (permalink / raw)
  Cc: guile-user, Rob Browning

tomas@fabula.de writes:

> Yes. I think this looks very nice. Some might argue for something more
> abstract than an integer (a signal_t or whatnot) -- I wouldn't oppose,
> but I'm very happy with what you propose.

Yes, I started with scm_t_signal_token, but the OS signal identifiers
are already ints and when we want to mix them, we need to use ints as
well.

I am not starting to work on this immediately, tho.  Anyone?  Tomas?
The file to look at would be scmsigs.c


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-02 13:18               ` Marius Vollmer
@ 2005-02-02 13:47                 ` tomas
  0 siblings, 0 replies; 35+ messages in thread
From: tomas @ 2005-02-02 13:47 UTC (permalink / raw)
  Cc: guile-user, Rob Browning, tomas


[-- Attachment #1.1: Type: text/plain, Size: 1068 bytes --]

On Wed, Feb 02, 2005 at 02:18:14PM +0100, Marius Vollmer wrote:
> tomas@fabula.de writes:
> 
> > Yes. I think this looks very nice. Some might argue for something more
> > abstract than an integer (a signal_t or whatnot) -- I wouldn't oppose,
> > but I'm very happy with what you propose.
> 
> Yes, I started with scm_t_signal_token, but the OS signal identifiers
> are already ints and when we want to mix them, we need to use ints as
> well.

...unless you let scm_create_new_os_signal () take an integer parameter
(the OS signal identifier) or a magic constant (NEW_OS_SIGNAL or something
like that, to return a `new' signal token).

As I said, to me this is very reasonable. I too lean towards the
``int'' side. To me integers seem quite abstract already ;-)

> I am not starting to work on this immediately, tho.  Anyone?  Tomas?
> The file to look at would be scmsigs.c

I'll have a look at it on Fryday/weekend. At the moment I'm at a customer's
place and I bet they don't even *know* I have Internet connectivity ;-)

Thanks
-- tomás

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 140 bytes --]

_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-02  0:38     ` Ken Raeburn
@ 2005-02-07  0:48       ` Kevin Ryde
  2005-02-08 21:45         ` Ken Raeburn
  2005-02-09 12:17         ` Marius Vollmer
  2005-02-09 12:13       ` Marius Vollmer
  1 sibling, 2 replies; 35+ messages in thread
From: Kevin Ryde @ 2005-02-07  0:48 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:
>
> The problem is, if there are any case where it would be needed, then we 
> need to use it everywhere there could be a potential problem.  
> Depending on just how it works out, that could mean essentially 
> declaring some of the scheme object types (like cons cells) as 
> volatile, which would be poor for performance.

I'd think it shouldn't hurt too much.  A store written in the code
probably means a store should be done :-).  Optimizations for local
variables etc should be unchanged, just memory ops become exactly as
written.

> And volatile declarations may fix the possibility of storing incomplete 
> values, but I don't think it would deal with the cross-thread memory 
> access ordering issue.

I think we have to assume all threads see memory ops in the order
they're done (anything else is too crazy), and with that assumption
and some care libguile ought to be ok.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-07  0:48       ` Kevin Ryde
@ 2005-02-08 21:45         ` Ken Raeburn
  2005-02-09 12:17         ` Marius Vollmer
  1 sibling, 0 replies; 35+ messages in thread
From: Ken Raeburn @ 2005-02-08 21:45 UTC (permalink / raw)


On Feb 6, 2005, at 19:48, Kevin Ryde wrote:
> Ken Raeburn <raeburn@raeburn.org> writes:
>> The problem is, if there are any case where it would be needed, then 
>> we
>> need to use it everywhere there could be a potential problem.
>> Depending on just how it works out, that could mean essentially
>> declaring some of the scheme object types (like cons cells) as
>> volatile, which would be poor for performance.
>
> I'd think it shouldn't hurt too much.  A store written in the code
> probably means a store should be done :-).  Optimizations for local
> variables etc should be unchanged, just memory ops become exactly as
> written.

And a read becomes a read, with no option for combining multiple reads 
from the location.  I think that's where the performance might not be 
so good.

>> And volatile declarations may fix the possibility of storing 
>> incomplete
>> values, but I don't think it would deal with the cross-thread memory
>> access ordering issue.
>
> I think we have to assume all threads see memory ops in the order
> they're done (anything else is too crazy), and with that assumption
> and some care libguile ought to be ok.

Then you will never have a correct port to the Alpha, at least.  The 
Alpha architecture specification allows for rearrangement of accesses 
except when a memory barrier instruction is used.  (Memory operations 
issued before the MB must precede those issued after it.)  I'd be very 
surprised if other modern architectures didn't also use various weak 
memory models, for performance in multiprocessor configurations.



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-01 17:37 ` Some introductory docs about C level threading Ken Raeburn
  2005-02-01 23:40   ` Kevin Ryde
@ 2005-02-09 12:04   ` Marius Vollmer
  1 sibling, 0 replies; 35+ messages in thread
From: Marius Vollmer @ 2005-02-09 12:04 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:

>>    It is safe to use `SCM_CAR' and `SCM_CDR' on the local variable LIST
>> once it is known that the variable contains a pair.  The contents of
>> the pair might change spontaneously, but it will always stay a valid
>> pair (and a local variable will of course not spontaneously point to a
>> different Scheme object).
>
> But is it guaranteed that, without locking, SCM_CAR and SCM_CDR will
> always return the "before" or "after" values while another thread is
> modifying them, and not some corrupted intermediate form?  Given
> typical data alignment and access, and hardware memory management
> techniques, and the small size of a SCM value, I'm not aware of a
> situation where it would be at all likely to happen, but I'm also not
> aware of any guarantee that it won't.

I'd say we pretty much have to assume this behavior, even without a
guarantee, when we want to have truly concurrent threads.  The
alternative would be to only allow one thread to access the heap at
any one time.

I am seriously willing to consider this alternative, but right now,
let's see how far we can get with concurrent threads.

> Though, even without weird memory management issues, consider:
>    SCM_SETCAR(x, SCM_I_MAKINUM(i >> 2))    i some external int var
>   -> (....x)[0] = ((... i >> 2) << 2 + scm_tc2_int)
>   -> copy i, masking off bottom two bits, into target location; then
> add in scm_tc2_int
>
> If SCM_CAR(x) is read at just the wrong time, the tag bits might not
> be correct.

Yes, this is a real issue (which I wasn't aware of previously).  More
about this further down in this thread.

> It may also be the case that if both the car and cdr of the pair (or
> indeed, any two separate locations) are modified in one thread and
> read in another, the memory accesses could be reordered (by the
> compiler, or even by the CPU these days) such that the read-back
> contents of the pair don't seem to match the "before" or "after"
> values or even the expected intermediate state where the first-listed
> modification has been done but the second has not.

This behavior can be allowed, as Guile only has to guarantees that a
single SCM is modified atomically.  Thus, the car and cdr will always
be a valid SCM value, but they might be totally arbitrary and your
code must make no assumptions about it.

In order to use a pair from two threads meaningfully, you need to put
in some synchronization, such as a mutex.  But this is left to the
upper layers of the program, where these issues can be solved.

> If someone's got lots more experience with multithreaded systems and
> wants to say I'm wrong, great.  I've been thinking about this a bit
> lately, trying to make a pile of code thread-safe at work, but I'm
> mostly coming at it from a theoretical perspective.

Me too. ;-)  (My pile of code is actually Guile itself.)


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-01 23:40   ` Kevin Ryde
  2005-02-02  0:38     ` Ken Raeburn
@ 2005-02-09 12:08     ` Marius Vollmer
  2005-02-09 16:33       ` Doug Evans
  2005-02-09 20:19       ` Kevin Ryde
  1 sibling, 2 replies; 35+ messages in thread
From: Marius Vollmer @ 2005-02-09 12:08 UTC (permalink / raw)
  Cc: guile-user, Ken Raeburn

Kevin Ryde <user42@zip.com.au> writes:

> You can force load/stores to be exactly as given using `volatile', [...]

How would that work exactly?  Can we flag each assignment operation as
volatile, or would the SCM type need to be made volatile?  Would this
be a reason to remove SCM_SMOB_OBJECT_LOC, for example, and to
disallow pointers to SCM in general (since we must control all
assignments)?


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-02  0:38     ` Ken Raeburn
  2005-02-07  0:48       ` Kevin Ryde
@ 2005-02-09 12:13       ` Marius Vollmer
  2005-02-09 18:10         ` Ken Raeburn
  1 sibling, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-02-09 12:13 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:

>> SCM type will mean it's atomic.
>
> If use of the SCM type is assumed to be atomic in terms of CPU memory
> access and inter-CPU memory consistency, that's fine, but it should be
> documented as such -- and we should acknowledge that ports to
> architectures where that assumption does not hold may not be possible.

Yes, this is exactly my intention.

> [...]
> Depending on just how it works out, that could mean essentially
> declaring some of the scheme object types (like cons cells) as
> volatile, which would be poor for performance.

That would be no show-stopper: if Guile can only be correct with poor
performance on some platform, than we have to swallow that.

> And volatile declarations may fix the possibility of storing
> incomplete values, but I don't think it would deal with the
> cross-thread memory access ordering issue.

As long as accesses to SCM values are atomic, the ordering of
loads/stores across threads can be arbitrary.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-07  0:48       ` Kevin Ryde
  2005-02-08 21:45         ` Ken Raeburn
@ 2005-02-09 12:17         ` Marius Vollmer
  2005-02-09 20:26           ` Kevin Ryde
  1 sibling, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-02-09 12:17 UTC (permalink / raw)
  Cc: guile-user, Ken Raeburn

Kevin Ryde <user42@zip.com.au> writes:

> I think we have to assume all threads see memory ops in the order
> they're done (anything else is too crazy),

Why?  I think it is very common to have weakly ordered memory models
in SMP systems these days, and we really can't assume a strong order.
I also think we can tolerate such a weak ordering, in the sense that
Guile remains 'thread-robust', i.e., doesn't corrupt its own heap such
that the GC will crash, for example.

Whether the heap remains in a state that makes sense to the
application, well, that problem is not solved by Guile automatically.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 12:08     ` Marius Vollmer
@ 2005-02-09 16:33       ` Doug Evans
  2005-02-10 11:15         ` Marius Vollmer
  2005-02-09 20:19       ` Kevin Ryde
  1 sibling, 1 reply; 35+ messages in thread
From: Doug Evans @ 2005-02-09 16:33 UTC (permalink / raw)
  Cc: guile-user, Ken Raeburn, Kevin Ryde

Marius Vollmer writes:
 > Kevin Ryde <user42@zip.com.au> writes:
 > 
 > > You can force load/stores to be exactly as given using `volatile', [...]
 > 
 > How would that work exactly?  Can we flag each assignment operation as
 > volatile, or would the SCM type need to be made volatile?  Would this
 > be a reason to remove SCM_SMOB_OBJECT_LOC, for example, and to
 > disallow pointers to SCM in general (since we must control all
 > assignments)?

I don't think GCC uses `volatile' to emit the memory barriers
Ken is refering to.  Using `volatile' to solve this problem
seems to me to be a non-starter.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 12:13       ` Marius Vollmer
@ 2005-02-09 18:10         ` Ken Raeburn
  2005-02-10 12:05           ` Marius Vollmer
  0 siblings, 1 reply; 35+ messages in thread
From: Ken Raeburn @ 2005-02-09 18:10 UTC (permalink / raw)
  Cc: guile-user

On Feb 9, 2005, at 07:13, Marius Vollmer wrote:
>> And volatile declarations may fix the possibility of storing
>> incomplete values, but I don't think it would deal with the
>> cross-thread memory access ordering issue.
> As long as accesses to SCM values are atomic, the ordering of
> loads/stores across threads can be arbitrary.

I think someone might be tempted to do something like:

thread 1, on cpu 1, with guile core mutex locked:

(precondition: z is a pair, SCM_CAR(z) is a pair)
allocate cons cell x
fill in x.car = v1
fill in x.cdr = v2
SCM_SETCAR(z, x)

thread 2, on cpu 2, running without lock:

set t = SCM_CAR(z) # atomic, so we always get before or after, right?
read SCM_CAR(t) # should Just Work?

With weak memory ordering, and no locking during this sequence in 
either thread, I don't think we get any guarantee that SCM_CAR(t) will 
get v1 instead of the uninitialized contents of the cons cell as pulled 
off of the free list.  Especially if it's one that cpu 2 happened to 
examine recently (perhaps it ran the GC pass) and thus has it in cache. 
  I think you need a memory synchronization operation in each to 
guarantee this.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 12:08     ` Marius Vollmer
  2005-02-09 16:33       ` Doug Evans
@ 2005-02-09 20:19       ` Kevin Ryde
  1 sibling, 0 replies; 35+ messages in thread
From: Kevin Ryde @ 2005-02-09 20:19 UTC (permalink / raw)
  Cc: guile-user

Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>
> Kevin Ryde <user42@zip.com.au> writes:
>
>> You can force load/stores to be exactly as given using `volatile', [...]
>
> How would that work exactly?  Can we flag each assignment operation as
> volatile, or would the SCM type need to be made volatile?

Volatile marks a variable or a pointer location as possibly changing
mysteriously (other threads in this case), so it'd go on pointers to
SCMs and probably on global SCM vars.  Newly created SCMs wouldn't
need it, they're as yet unknown to other threads.

> Would this be a reason to remove SCM_SMOB_OBJECT_LOC, for example,

Probably not, but an application might need to think about whether it
should use "volatile SCM *" instead of "SCM *".


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 12:17         ` Marius Vollmer
@ 2005-02-09 20:26           ` Kevin Ryde
  2005-02-10 11:36             ` Marius Vollmer
  0 siblings, 1 reply; 35+ messages in thread
From: Kevin Ryde @ 2005-02-09 20:26 UTC (permalink / raw)
  Cc: guile-user

Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>
> Why?

I'm thinking that you build a list structure or whatever, then plonk
it somewhere other threads can access it.  When another thread can see
that final store, you'd like it to see all the stores that preceded it
which built the structure.

Maybe that's too optimistic, but at the scheme level I think it's what
you'd like to end up with, ie. data usable from any thread without
special transfers or syncs.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 16:33       ` Doug Evans
@ 2005-02-10 11:15         ` Marius Vollmer
  0 siblings, 0 replies; 35+ messages in thread
From: Marius Vollmer @ 2005-02-10 11:15 UTC (permalink / raw)
  Cc: guile-user, Ken Raeburn, Kevin Ryde

Doug Evans <dje@transmeta.com> writes:

> Marius Vollmer writes:
>  > Kevin Ryde <user42@zip.com.au> writes:
>  > 
>  > > You can force load/stores to be exactly as given using `volatile', [...]
>  > 
>  > How would that work exactly?  Can we flag each assignment operation as
>  > volatile, or would the SCM type need to be made volatile?  Would this
>  > be a reason to remove SCM_SMOB_OBJECT_LOC, for example, and to
>  > disallow pointers to SCM in general (since we must control all
>  > assignments)?
>
> I don't think GCC uses `volatile' to emit the memory barriers
> Ken is refering to.  Using `volatile' to solve this problem
> seems to me to be a non-starter.

There are two issues here: one is guaranteeing atomic access to SCM
values (SCM is a pointer type, i.e., a full word).  The other is
synchronizing memory (weekly ordered or not), so that all CPUs have a
coherent view of memory at a certain point in time.

We only need to solve the first issue for all accesses to SCM values
(I think).  The second issue might need to be addressed for a certain
small number of situations, but not in general for all accesses.

To put it differently, the question is what kind of memory model to
present to a multi-threaded Scheme program.

1) We must guarantee atomic accesses to values (where a 'value' is a
machine word) because a Scheme program must not crash because of
corrupted values, even when the threads of the program are not
properly synchronized.

2) We can get by with a weakly ordered memory model since out-of-order
stores do not crash the system.  They might cause the Scheme program
to be incorrect, but you need to properly synchronize it anyway.


As to 1), hopefully 'volatile' will guarantee atomic loads and stores.
Does it?  It will be enough if it just happens to work on the most
important SMP platforms.  (I.e., I could imagine that there is no way
to atomically read a 32-bit word on a CPU with a 16-bit bus, but I can
also imagine that these CPUs are not used in SMP systems any more that
we need to care about.)

As to 2), the Single Unix Specification says that a number of pthread
functions (and others) synchronize memory between threads, so that
using mutexes etc in the normal way will take care of memory
coherency, including weakly ordered memory.


Does this make sense?  I am still grabbling with the fundamentals, it
seems...


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 20:26           ` Kevin Ryde
@ 2005-02-10 11:36             ` Marius Vollmer
  0 siblings, 0 replies; 35+ messages in thread
From: Marius Vollmer @ 2005-02-10 11:36 UTC (permalink / raw)
  Cc: guile-user

Kevin Ryde <user42@zip.com.au> writes:

> Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>>
>> Why?
>
> I'm thinking that you build a list structure or whatever, then plonk
> it somewhere other threads can access it.  When another thread can see
> that final store, you'd like it to see all the stores that preceded it
> which built the structure.

Yes, that is a very good example.  Hmm, I would say that it is OK to
_not_ guarantee that the second thread sees all the stores of the
first thread when it accesses the structure, _except_ that the
structure it guaranteed to be a valid Scheme object.

Of course, you want the second thread to see all the stores.  For
that, you need to do something special in you Scheme program, such as
protecting the global variable with a mutex, although the store into
it is expected to be atomic and thus wouldn't normally need
protection.

Hmm.

> Maybe that's too optimistic, but at the scheme level I think it's what
> you'd like to end up with, ie. data usable from any thread without
> special transfers or syncs.

Yes, but multi-threaded programming does not seem to work this way.  I
would agree that it sucks, and that people should rather make
programming easier (by guaranteeing memory consistency between threads
of a single process, say) instead of going for artificial benchmark
numbers.  Memory coherency should probably be an option of mmap and
only the truly brave would turn it off...


We could try to offer a nicer memory model to Scheme programs, but we
would have to do it by disallowing true concurrency, I think.  We had
this option a while ago, with the coop-pthreads.  It was a simple
implementation of cooperating threads on top of pthreads.  Only one
thread would be in guile mode at any one time.  As I said elsewhere, I
like this idea very much, but right now, I am trying to go for full
concurrency.  The problem will likely be that in the end, Guile will
work good enough in practice, but there will always be the nagging
doubt whether it really is completely correct.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-09 18:10         ` Ken Raeburn
@ 2005-02-10 12:05           ` Marius Vollmer
  2005-02-10 19:59             ` Ken Raeburn
  0 siblings, 1 reply; 35+ messages in thread
From: Marius Vollmer @ 2005-02-10 12:05 UTC (permalink / raw)
  Cc: guile-user

Ken Raeburn <raeburn@raeburn.org> writes:

> I think someone might be tempted to do something like:
>
> thread 1, on cpu 1, with guile core mutex locked:

(There is no guile core mutex.  Is it relevant to the discussion
below?)

> (precondition: z is a pair, SCM_CAR(z) is a pair)
> allocate cons cell x
> fill in x.car = v1
> fill in x.cdr = v2
> SCM_SETCAR(z, x)
>
> thread 2, on cpu 2, running without lock:
>
> set t = SCM_CAR(z) # atomic, so we always get before or after, right?
> read SCM_CAR(t) # should Just Work?

Yes, I had planned for this to just work...

> With weak memory ordering, and no locking during this sequence in
> either thread, I don't think we get any guarantee that SCM_CAR(t) will
> get v1 instead of the uninitialized contents of the cons cell as
> pulled off of the free list.

Yes, I now realize that at least initialization needs to have some
kind of memory synchronization after it.  Would declaring x.car and
x.cdr as volatile do it?

> Especially if it's one that cpu 2 happened to examine recently
> (perhaps it ran the GC pass) and thus has it in cache. I think you
> need a memory synchronization operation in each to guarantee this.

Needing to have the synch operation in all threads would be really
bad... is it really necessary?  If it is, I would get serious doubts
whether we can achieve the SCM is always valid' goal with full
concurrency.


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-02-10 12:05           ` Marius Vollmer
@ 2005-02-10 19:59             ` Ken Raeburn
  0 siblings, 0 replies; 35+ messages in thread
From: Ken Raeburn @ 2005-02-10 19:59 UTC (permalink / raw)
  Cc: guile-user

On Feb 10, 2005, at 07:05, Marius Vollmer wrote:
> Ken Raeburn <raeburn@raeburn.org> writes:
>> I think someone might be tempted to do something like:
>>
>> thread 1, on cpu 1, with guile core mutex locked:
>
> (There is no guile core mutex.  Is it relevant to the discussion
> below?)

Oh.  Hm,  I think I was reading a lot more into the 
scm_enter/leave_guile stuff than you had actually written, or 
remembering it wrong.  I've seen code for other languages work this way 
(one thread at a time allowed in the interpreter and/or messing with 
object contents directly), and I guess I assumed too much and read too 
little. :-(

So, on re-reading, I take it that scm_leave_guile isn't about locking 
anything, it's about blocking outside of Guile, and not screwing up GC 
or async signals.  Can GC happen between scm_leave_guile and the 
following scm_enter_guile call?  If so, I assume scm_leave_guile 
records some info about where the current stack pointer is; so where 
does the stack scanner look for SCM values that might only exist in 
registers?

As for the details below, I don't think this affects much; I think the 
key point is that a thread *isn't* using a mutex.

>> (precondition: z is a pair, SCM_CAR(z) is a pair)
>> allocate cons cell x
>> fill in x.car = v1
>> fill in x.cdr = v2
>> SCM_SETCAR(z, x)
>>
>> thread 2, on cpu 2, running without lock:
>>
>> set t = SCM_CAR(z) # atomic, so we always get before or after, right?
>> read SCM_CAR(t) # should Just Work?
>
> Yes, I had planned for this to just work...
>
>> With weak memory ordering, and no locking during this sequence in
>> either thread, I don't think we get any guarantee that SCM_CAR(t) will
>> get v1 instead of the uninitialized contents of the cons cell as
>> pulled off of the free list.
>
> Yes, I now realize that at least initialization needs to have some
> kind of memory synchronization after it.  Would declaring x.car and
> x.cdr as volatile do it?

I don't think so.  I think you need memory sync operations in each 
thread, and you need to ensure that thread 1 finishes its memory sync 
before thread 2 starts its memory sync.

>> Especially if it's one that cpu 2 happened to examine recently
>> (perhaps it ran the GC pass) and thus has it in cache. I think you
>> need a memory synchronization operation in each to guarantee this.
>
> Needing to have the synch operation in all threads would be really
> bad... is it really necessary?  If it is, I would get serious doubts
> whether we can achieve the SCM is always valid' goal with full
> concurrency.

I believe it is necessary.  But that's part of why I was asking for 
people with significant real-world experience in this area to chime in. 
:-)

I'd love to have full concurrency.  But correctness is IMNSHO more 
important, and I'm not sure we can get both, at least not with adequate 
performance as well.

If we can find some way to cope with initialization (perhaps GC and new 
storage allocation could end with memory sync operations in all 
threads, and all free-list objects in an initialized state with no 
references to other free-list objects?), and assume atomicity but not 
synchronization for SCM value modifications (though pair contents and 
other containers might have to become "volatile" for that to work), we 
might still be able to push synchronization around later modifications 
into application Scheme/C code, I'm not sure....

Ken


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Some introductory docs about C level threading
  2005-01-24 19:23   ` Marius Vollmer
@ 2005-02-15  4:11     ` Robert Uhl
  0 siblings, 0 replies; 35+ messages in thread
From: Robert Uhl @ 2005-02-15  4:11 UTC (permalink / raw)
  Cc: guile-user, Neil Jerram

Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>
> > I just spotted one spelling mistake: your "honer" should be "honour"
> > (or perhaps "honor" - are the Guile docs supposed to be British
> > English or American English?).
>
> Hmm, I can't say.  The canonical English of computer stuff is probably
> American English...

But then a good many computer folks have been Anglophiles; that with the
vastly greater number of English-speakers which use proper spelling
should indicate a preference for British English...

But I'm an American with LANG=en_GB.UTF-8, so I'm obviously a crank...

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
The spectrum of wit explored by television comedy runs largely between
the pre- and the post-coital.                          --David B. Hart


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-user


^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2005-02-15  4:11 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-21 18:29 Some introductory docs about C level threading Marius Vollmer
2005-01-21 21:20 ` Neil Jerram
2005-01-24 19:23   ` Marius Vollmer
2005-02-15  4:11     ` Robert Uhl
2005-01-22 12:37 ` tomas
2005-01-24 19:28   ` Marius Vollmer
2005-01-25  9:06     ` tomas
2005-01-25 15:58       ` Rob Browning
2005-01-25 16:01         ` Rob Browning
2005-01-26  9:05         ` tomas
2005-02-01 16:01           ` Marius Vollmer
2005-02-02  9:31             ` tomas
2005-02-02 13:18               ` Marius Vollmer
2005-02-02 13:47                 ` tomas
2005-01-23 23:34 ` Kevin Ryde
2005-01-24 19:31 ` Some new reference docs about initialization Marius Vollmer
2005-01-24 20:27   ` Andreas Rottmann
2005-01-24 22:00     ` Marius Vollmer
2005-02-01 17:37 ` Some introductory docs about C level threading Ken Raeburn
2005-02-01 23:40   ` Kevin Ryde
2005-02-02  0:38     ` Ken Raeburn
2005-02-07  0:48       ` Kevin Ryde
2005-02-08 21:45         ` Ken Raeburn
2005-02-09 12:17         ` Marius Vollmer
2005-02-09 20:26           ` Kevin Ryde
2005-02-10 11:36             ` Marius Vollmer
2005-02-09 12:13       ` Marius Vollmer
2005-02-09 18:10         ` Ken Raeburn
2005-02-10 12:05           ` Marius Vollmer
2005-02-10 19:59             ` Ken Raeburn
2005-02-09 12:08     ` Marius Vollmer
2005-02-09 16:33       ` Doug Evans
2005-02-10 11:15         ` Marius Vollmer
2005-02-09 20:19       ` Kevin Ryde
2005-02-09 12:04   ` Marius Vollmer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).