Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Threads

10 views
Skip to first unread message

Dan Sugalski

unread,
Dec 22, 2003, 12:23:56 PM12/22/03
to perl6-i...@perl.org
Since they've come up, here's the scheme I've been pondering, based
in large part on experience with POSIX threads at the C level,
POSIX-style threads at the interpreter level (with perl 5's
5.005-style threads), and the interpreter/semi-fork style threads
that perl 5's using now.

First off, the most important thing is that we absolutely guarantee
that interpreter internal data structures are consistent and
threadsafe. Nothing that bytecode does should be able to corrupt the
internals of parrot. (We'll not talk about C extensions here--they
can screw things up in massive and horribly creative ways, of course)

Second, we're assuming that the *non* threaded case is the common
case. (This is definitely the assumption that I'm most expecting to
regret in the future)

Third, we're assuming that we are *not* providing any sort of
guarantees to user code about threads. User-level thread safety
without user coding for it's one of those "solve the halting problem"
things. While it'd be cool to solve, we've got better things to do
before the sun goes nova. :)

So, the scheme is this.

1) Only PMCs may be shared across interpreters.

2) PMCs always live in the interpreter in which they were allocated

3) Only shareable PMCs may cross interpreters

4) Putting a PMC into a shared container shares the PMC and anything
that the PMC points to. (This may involve a cascade of sharing. Too
bad) PMCs may pitch an exception instead of sharing their contents

5) *Secondary* sharing failures are interpreter-killing fatal errors.
Primary sharing failures are exceptions. That is, if you share
something and that thing says no, it's an exception. If you share
something and that something goes and shares something else and that
fails, it's fatal.

6) Immutable things may be shared across interpreters with no
synchronization or need for sub-sharing. Other than constants we
don't have many of those

7) Immutable things may *not* point to mutable things. The converse is OK.

8) We're probably going to have to rejig the string functions some,
and access them via a vtable off strings or something of the sort, so
we can swap in and out threadsafe memory allocation and string
allocation routines.

9) We need to add a share() entry to the vtable list for PMCs.

As to what gets shared and not shared...

There are three types of thread spawning we're going to do.

Type 1) Start a new thread with a new interpreter that shares
*nothing* with the original, not even any communication.

Type 2) Start a new thread with a new interpreter and communicate
with it in what's essentially an opto-isolated way. Done by sending
messages to the other thread and waiting for acknowledgement.
Messages received from another thread can be considered read-only and
immutable, and should be copied and acknowledged as soon as possible
into the receiving thread

Type 3) Start a new thread with a new interpreter and put it into the
current thread pool. Threads of this sort may share everything, but
aren't required to do so.

Type 1 threads start fresh, and basically get nothing but a chunk of
bytecode and whatever that bytecode instantiates. This is essentially
the same as firing up a brand new parrot process, except it's in a
shared memory space. These threads can be free-running and don't
require any sort of locking as they're completely independent. We
count on the OS and system libraries to provide adequate locking
where needed. (System memory allocation, system IO, and the like)

Type 2 threads are a bit more tightly coupled. When started, the
interpreter may optionally mark its contents as cloneable into the
new interpreter, in which case it gets a copy of all the creating
thread's data and whatnot. (We can COW this or
whatever--optimizations are fine as long as it looks like a copy)

With type 2 threads, libraries get their "You're being instantiated"
function called, but do not get their "you're being loaded" function
called, as they do when they're originally loaded. That's because
they're *not* being loaded, just re-instantiated into a new thread.
This may or may not do anything.

Type 3 threads clone off their internals (once again COWing
themselves if we want) and then present everything as shared. Any
library loaded in one interpreter is loaded into all of them, and we
don't (I think, this can be argued) call the "you're being
instantiated" function more than once. Once loaded, a package and all
its data are visible to every thread in the type 3 thread group.

There'll be more, and soon, but let's hack into this part to start
with and we'll go from here.
--
Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Josh Wilmes

unread,
Dec 22, 2003, 1:49:12 PM12/22/03
to Dan Sugalski, perl6-i...@perl.org
At 12:23 on 12/22/2003 EST, Dan Sugalski <d...@sidhe.org> wrote:

> Second, we're assuming that the *non* threaded case is the common
> case. (This is definitely the assumption that I'm most expecting to
> regret in the future)

I think it might be good to get started on regretting that as soon as
possible ;-)

--Josh

Dan Sugalski

unread,
Dec 22, 2003, 2:14:32 PM12/22/03
to Josh Wilmes, perl6-i...@perl.org

Oh, no worries there. :)

Still, at the moment, so far as I can tell, most perl, python, and
ruby programs that are run are run single-threaded, and as such that
mode ought to have the fastest run. Threaded programs are less common
(though certainly not unknown) and as such they should be as
efficient as possible but, when a tradeoff's to be made, the
single-thread case should win unless it jeapordizes stability or
truly screws performance in the multithreaded case.

Note that this doesn't refer to the case where we have multiple
free-running interpreters in a process that have no interaction--the
type one case. (And mostly the type 2 case)

Leopold Toetsch

unread,
Dec 22, 2003, 4:09:24 PM12/22/03
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

I get 1) - 7) and it totally matches my thoughts :)

> 8) We're probably going to have to rejig the string functions some,
> and access them via a vtable off strings or something of the sort, so
> we can swap in and out threadsafe memory allocation and string
> allocation routines.

Can you elaborate on that a bit more? Strings are (as any other managed
parrot resources) living inside the separated memory pools. Where do you
see problems?

> 9) We need to add a share() entry to the vtable list for PMCs.

To swap in the LOCK-protected vtable variant or to morph() SELF into a
shared reference?

> Type 1) Start a new thread with a new interpreter that shares
> *nothing* with the original, not even any communication.

faking fork() for Win32?

[ snipped a lot ]

> There'll be more, and soon, but let's hack into this part to start
> with and we'll go from here.

Actually, let's please address things as they arrive. The big picture is
very reasonable and of ocurse necessary. OTOH there are many small
design issues involved - I did address 2 of these recently - I'd be
really glad, if you could have a look at these too ;)

leo

Dan Sugalski

unread,
Dec 22, 2003, 4:38:36 PM12/22/03
to l...@toetsch.at, perl6-i...@perl.org
At 10:09 PM +0100 12/22/03, Leopold Toetsch wrote:
>Dan Sugalski <d...@sidhe.org> wrote:
>
>I get 1) - 7) and it totally matches my thoughts :)
>
>> 8) We're probably going to have to rejig the string functions some,
>> and access them via a vtable off strings or something of the sort, so
>> we can swap in and out threadsafe memory allocation and string
>> allocation routines.
>
>Can you elaborate on that a bit more? Strings are (as any other managed
>parrot resources) living inside the separated memory pools. Where do you
>see problems?

Well, consider reallocating a string because it's grown. That
requires allocating memory from the interpreter that the string
header comes from, which might not be the current interpreter. That
means when we reallocate the memory we need to lock the pool the
memory came from, and the garbage collector for that interpreter
needs to respect the lock as well. Otherwise we can end up with
multiple allocations from the same pool without synchronization, or
the GC yanking the contents around without synchronization, both of
which are very bad.

Also, there's the issue of just accessing the string data itself. If
the string is from the current interpreter we're safe--there's no way
we can be in the middle of a GC run at the same time we access the
string's data pointer. That's not the case with strings from a
different interpreter--we could be trying to get at the string data
while the GC is in the process of moving it around.

> > 9) We need to add a share() entry to the vtable list for PMCs.
>
>To swap in the LOCK-protected vtable variant or to morph() SELF into a
>shared reference?

Yes. Either way will work.

> > Type 1) Start a new thread with a new interpreter that shares
>> *nothing* with the original, not even any communication.
>
>faking fork() for Win32?

Fork's more a full COW'd type two thing, as it gets a copy of the
environment. It's often useful to have a pool of semi-independent or
completely independent interpreter threads in an embedded context. A
multiuser online game, for example, might want a number of
independent threads for different players, a web plugin might want a
separate independent thread for each instance of the plugin on a
page, or someone may be doing something I've not thought of.

> > There'll be more, and soon, but let's hack into this part to start
>> with and we'll go from here.
>
>Actually, let's please address things as they arrive. The big picture is
>very reasonable and of ocurse necessary. OTOH there are many small
>design issues involved - I did address 2 of these recently - I'd be
>really glad, if you could have a look at these too ;)

I'll dig into 'em. Part of the reason I wanted to hold off a bit was
that I didn't want to be in the situation of getting some of the
details done right and then have to throw them out because the
assumptions they were based on got invalidated. :)

Elizabeth Mattijsen

unread,
Dec 22, 2003, 5:47:59 PM12/22/03
to Josh Wilmes, Dan Sugalski, perl6-i...@perl.org
Hmm... this has become more of a rambling rather than a coherent list
of reasons....

I think assuming the *non* threaded case to be the most common case,
and optimizing for that, is a bad decision.

In that respect, I think we need to think out of the box and take a
leap of faith here.

If you realize that most systems out there have threads integrated
into the core of the OS, I think it is a very *nix centric assumption
that single threaded is the most common occurance.

I think that if you want to have an ultra-fast single threaded
program, you would program it in C.

If you want a program that you want to be able to run anywhere using
a fast virtual machine, you want to use Parrot. And I think Parrot
should come with threads (or whatever you would call program
controlled multi-processing) as an integral part of the system.

It's easier to fake fork with threads, than it is to fake threads
with fork. Trust me, I've been there...

If the JIT compiler finds out that no threads are being used, it can
optimize for that.

Liz

Elizabeth Mattijsen

unread,
Dec 22, 2003, 5:59:05 PM12/22/03
to Dan Sugalski, Josh Wilmes, perl6-i...@perl.org
At 14:14 -0500 12/22/03, Dan Sugalski wrote:
>At 1:49 PM -0500 12/22/03, Josh Wilmes wrote:
>>I think it might be good to get started on regretting that as soon as
>>possible ;-)
>Still, at the moment, so far as I can tell, most perl, python, and
>ruby programs that are run are run single-threaded, and as such that
>mode ought to have the fastest run.

I wonder whether that is a good reason. Parrot originally came out
of a desire to make a Perl 6 engine. In which threads, co-routines,
events or whatever, are an integral part of the system. What Perl,
Python and Ruby programs do now, should carry less weight than what
all of these systems, and who knows what other languages that want to
build on top of Parrot, want to be able to do in the future.

People will not migrate from Perl 5 to Perl 6 because it will be able
to run the same application faster. If that iis the goal, you get
bigger hardware and your done with much less fear of migration
problems. People _will_ want to move from Perl 5 to Perl 6 because
of:
- good threads support
- good signalling support
- good event handling support
All of these more or less need a system that can quickly switch context.


>Threaded programs are less common (though certainly not unknown) and
>as such they should be as efficient as possible but, when a
>tradeoff's to be made, the single-thread case should win unless it
>jeapordizes stability or truly screws performance in the
>multithreaded case.

I think we need a change of mindset. Instead of seeing threaded
programs as the special case, we would need to see that the single
threaded program is the special case. See how many people use POE
for event handling, and through what hoops (Perl) Tk needs to jump
through to get proper event handling.

And yes, there are many, many single threaded Perl programs in the
world. Which will continue to run _fine_ on Perl 5.X.

Liz

Melvin Smith

unread,
Dec 22, 2003, 7:03:10 PM12/22/03
to Elizabeth Mattijsen, Dan Sugalski, Josh Wilmes, perl6-i...@perl.org
At 11:59 PM 12/22/2003 +0100, Elizabeth Mattijsen wrote:
>At 14:14 -0500 12/22/03, Dan Sugalski wrote:
>>At 1:49 PM -0500 12/22/03, Josh Wilmes wrote:
>>>I think it might be good to get started on regretting that as soon as
>>>possible ;-)
>>Still, at the moment, so far as I can tell, most perl, python, and ruby
>>programs that are run are run single-threaded, and as such that mode
>>ought to have the fastest run.
>
>I wonder whether that is a good reason. Parrot originally came out of a
>desire to make a Perl 6 engine. In which threads, co-routines,

More than that. Separating the runtime from the language front-end has been
key in my book.

> events or whatever, are an integral part of the system. What Perl,
> Python and Ruby programs do now, should carry less weight than what all
> of these systems, and who knows what other languages that want to build
> on top of Parrot, want to be able to do in the future.

I don't see how you can decide to attribute less "weight" to what Perl,
Python and Ruby programs do now.
Most programmers I know rank speed-of-prototyping and reduced line-count as
their favorite things about
the aforementioned languages.

>People will not migrate from Perl 5 to Perl 6 because it will be able to
>run the same application faster. If that iis the goal, you get bigger
>hardware and your done with much less fear of migration problems. People
>_will_ want to move from Perl 5 to Perl 6 because of:

Lots of companies are still developing on the same hardware they were
before Y2K. I'd bet they would welcome a
Perl implementation that got them 3-4x speedup for free for new code. I
will agree with you on legacy Perl apps, as most
of my clients are exactly as paranoid as you describe.

> - good threads support
> - good signalling support
> - good event handling support
>All of these more or less need a system that can quickly switch context.

I think it is unbalanced to regard threads & context-switching as the most
important aspect when dealing with languages that
do not lend themselves to optimization and static compilation.

If you really want reliable signal handling (to the point of worrying about
context switch overhead, we begin to sound
like we want a real-time OS and language), then you (at least currently)
don't write it in Perl/Python and _especially_
not Ruby. You write it in C/C++/Java/Objective-C, take yer pick.

>I think we need a change of mindset. Instead of seeing threaded programs
>as the special case, we would need to see that the single threaded program
>is the special case. See how many people use POE for event handling, and
>through what hoops (Perl) Tk needs to jump through to get proper event
>handling.

I don't think we are of the mindset that threading is so special and rare
that we will force threading programs to suffer in pain.
I don't see optimization like that. When Dan says we optimize for a common
case, it doesn't mean the uncommon case
won't be greatly improved as well. I expect any implementation of Parrot to
run single & multi-threaded programs many times
faster than the Perl5 engine.

I think I agree with you in spirit, that we should have high expectations
for Parrot and hopefully make the scripting
languages that we are running more realistic as all-around programming
languages. I see Parrot as an effort to
close the gap between Perl/Python/Ruby and C#/Java on the exact same
hardware, since significant advancements in
execution speed by the Java and C# implementations are pretty unlikely.
(They are already pretty fast)

-Melvin


Elizabeth Mattijsen

unread,
Dec 23, 2003, 4:07:38 AM12/23/03
to Melvin Smith, Dan Sugalski, Josh Wilmes, perl6-i...@perl.org
At 19:03 -0500 12/22/03, Melvin Smith wrote:
>At 11:59 PM 12/22/2003 +0100, Elizabeth Mattijsen wrote:
>> events or whatever, are an integral part of the system. What
>>Perl, Python and Ruby programs do now, should carry less weight
>>than what all of these systems, and who knows what other languages
>>that want to build on top of Parrot, want to be able to do in the
>>future.
>I don't see how you can decide to attribute less "weight" to what
>Perl, Python and Ruby programs do now.

Well, that argument goes the other way as well. I don't see how Dan
can decide to attribute more "weight" to single threaded
applications. Apart from the fact that Dan can and will do that, if
he feels so. ;-)


>Most programmers I know rank speed-of-prototyping and reduced
>line-count as their favorite things about
>the aforementioned languages.

No argument here.


>>People will not migrate from Perl 5 to Perl 6 because it will be
>>able to run the same application faster. If that iis the goal, you
>>get bigger hardware and your done with much less fear of migration
>>problems. People _will_ want to move from Perl 5 to Perl 6 because
>>of:
>Lots of companies are still developing on the same hardware they
>were before Y2K. I'd bet they would welcome a
>Perl implementation that got them 3-4x speedup for free for new
>code. I will agree with you on legacy Perl apps, as most
>of my clients are exactly as paranoid as you describe.

And rightfully so. Which in my book means that they will not migrate
to Perl 6. Hell, they even haven't migrated from Perl 5.00503 yet.
You expect them to migrate to Perl 6? On a brand new VM?


>> - good threads support
>> - good signalling support
>> - good event handling support
>>All of these more or less need a system that can quickly switch context.
>I think it is unbalanced to regard threads & context-switching as
>the most important aspect when dealing with languages that
>do not lend themselves to optimization and static compilation.

And I think that would be exactly the reason why Parrot would stand
out in the crowd.


>If you really want reliable signal handling (to the point of
>worrying about context switch overhead, we begin to sound
>like we want a real-time OS and language), then you (at least
>currently) don't write it in Perl/Python and _especially_
>not Ruby. You write it in C/C++/Java/Objective-C, take yer pick.

And it's the "currently" I would like to see change. We're working
for the future here, right?


>>I think we need a change of mindset. Instead of seeing threaded
>>programs as the special case, we would need to see that the single
>>threaded program is the special case. See how many people use POE
>>for event handling, and through what hoops (Perl) Tk needs to jump
>>through to get proper event handling.
>I don't think we are of the mindset that threading is so special and
>rare that we will force threading programs to suffer in pain.
>I don't see optimization like that. When Dan says we optimize for a
>common case, it doesn't mean the uncommon case
>won't be greatly improved as well. I expect any implementation of
>Parrot to run single & multi-threaded programs many times
>faster than the Perl5 engine.

I have no doubt about that. Running threaded applications faster
than Perl 5's ithreads, is however not a big target ;-). Perl 5's
ithreads are great for turning applications with a fork() mindset to
using threads. They are _lousy_ when trying to run applications with
a threaded mindset.

Ever tried starting more than 100 threads with ithreads? It takes
several _seconds_ on state-of-art hardware with any kind of real
setup. Which is basicallly what is killing mod_perl with other than
prefork MPM's.


>I think I agree with you in spirit, that we should have high
>expectations for Parrot and hopefully make the scripting
>languages that we are running more realistic as all-around
>programming languages.

Eh, I think you should cross out the "hopefully". It is Larry's
intention for Perl 6 to be a language for the next 30 years (IIRC).
I doubt he meant it as just another "scripting" language.


>I see Parrot as an effort to
>close the gap between Perl/Python/Ruby and C#/Java on the exact same
>hardware, since significant advancements in
>execution speed by the Java and C# implementations are pretty
>unlikely. (They are already pretty fast)

I think you are thinking too short term in that respect. ;-)


Liz

Leopold Toetsch

unread,
Dec 23, 2003, 4:06:46 AM12/23/03
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:
> At 10:09 PM +0100 12/22/03, Leopold Toetsch wrote:
>>Dan Sugalski <d...@sidhe.org> wrote:
>>
>>> 8) We're probably going to have to rejig the string functions some,

>>Can you elaborate on that a bit more? Strings are (as any other managed


>>parrot resources) living inside the separated memory pools. Where do you
>>see problems?

> Well, consider reallocating a string because it's grown. That
> requires allocating memory from the interpreter that the string
> header comes from, which might not be the current interpreter.

I see. A shared PerlString PMC is handled over to a different thread and
enlarged in that thread.

> That
> means when we reallocate the memory we need to lock the pool the
> memory came from, and the garbage collector for that interpreter
> needs to respect the lock as well.

That's the reason, why I came up with the vague idea: shared resources
have their own buffer/memory pools. I don't know, if that helps though.

But all this seems to indicate, that shared PMCs need an interpreter
back-ptr to reallocate resources. Not only strings got that problem:
enlarging shared arrays or hashes also have to use their own
header/memory pools.

While its not too complicated to get from an PObj* to the arena its time
consuming (more or less, depending on ARENA_DOD_FLAGS), it seems simpler
to have an interpreter back-pointer in the (shared) PMC.

> Also, there's the issue of just accessing the string data itself. If
> the string is from the current interpreter we're safe--there's no way
> we can be in the middle of a GC run at the same time we access the
> string's data pointer. That's not the case with strings from a
> different interpreter--we could be trying to get at the string data
> while the GC is in the process of moving it around.

Again, not only strings but all kind of containers using managed
resources suffer from that problem.

All that seems to imply, that we need two locks for shared access: one
for protecting DOD/GC and a second for the PMC. Any container (including
PerlStrings) would have to aquire the first (interpreter-global) lock,
while a PerlNum only needs the second per PMC mutex. Ugly.

leo

Melvin Smith

unread,
Dec 23, 2003, 1:31:00 PM12/23/03
to Elizabeth Mattijsen, Dan Sugalski, Josh Wilmes, perl6-i...@perl.org
At 10:07 AM 12/23/2003 +0100, Elizabeth Mattijsen wrote:
>>I think I agree with you in spirit, that we should have high expectations
>>for Parrot and hopefully make the scripting
>>languages that we are running more realistic as all-around programming
>>languages.
>
>Eh, I think you should cross out the "hopefully". It is Larry's intention
>for Perl 6 to be a language for the next 30 years (IIRC). I doubt he meant
>it as just another "scripting" language.

Lets not be unrealistic. Certain language features inherently make compile
time (and run-time)
optimizations hard or impossible. Perl 6 happens to have quite a handful of
them so it is no
surprise to me that we find we always seem to be a few cycles shy of
certain traditional
static languages.

>>I see Parrot as an effort to
>>close the gap between Perl/Python/Ruby and C#/Java on the exact same
>>hardware, since significant advancements in
>>execution speed by the Java and C# implementations are pretty unlikely.
>>(They are already pretty fast)
>
>I think you are thinking too short term in that respect. ;-)

Don't assume that because my opinion differs from your own that it means I
think in less grand scale than
you do. :)

It is much too early to decide if a particular optimization towards
single-threadness necessarily
hurts anything and there is certainly no reason to assume Parrot/Perl6
won't run threaded
applications well just because Perl5's ithreads don't.

-Melvin


Dan Sugalski

unread,
Dec 23, 2003, 2:46:42 PM12/23/03
to l...@toetsch.at, perl6-i...@perl.org
At 10:06 AM +0100 12/23/03, Leopold Toetsch wrote:
>Dan Sugalski <d...@sidhe.org> wrote:
>> At 10:09 PM +0100 12/22/03, Leopold Toetsch wrote:
>>>Dan Sugalski <d...@sidhe.org> wrote:
>>>
>>>> 8) We're probably going to have to rejig the string functions some,
>
>>>Can you elaborate on that a bit more? Strings are (as any other managed
>>>parrot resources) living inside the separated memory pools. Where do you
>>>see problems?
>
>> Well, consider reallocating a string because it's grown. That
>> requires allocating memory from the interpreter that the string
>> header comes from, which might not be the current interpreter.
>
>I see. A shared PerlString PMC is handled over to a different thread and
>enlarged in that thread.

Yep. Or an array or hash PMC gets expanded so the backing pool of
memory needs reallocation.

> > That
>> means when we reallocate the memory we need to lock the pool the
>> memory came from, and the garbage collector for that interpreter
>> needs to respect the lock as well.
>
>That's the reason, why I came up with the vague idea: shared resources
>have their own buffer/memory pools. I don't know, if that helps though.

Sort of, but you run into the issue of collecting that space across
threads, which can me an issue. You still need to go lock the pool,
but now all the threads are going to potentially have a single choke
point rather than multiple choke points.

>But all this seems to indicate, that shared PMCs need an interpreter
>back-ptr to reallocate resources. Not only strings got that problem:
>enlarging shared arrays or hashes also have to use their own
>header/memory pools.
>
>While its not too complicated to get from an PObj* to the arena its time
>consuming (more or less, depending on ARENA_DOD_FLAGS), it seems simpler
>to have an interpreter back-pointer in the (shared) PMC.

Yep, you're right. Let's make it happen. We can use the synchronize
pointer and hang a struct off of it with the owning interpreter and
the PMC mutex, along with other things we need as we come across them.

> > Also, there's the issue of just accessing the string data itself. If
>> the string is from the current interpreter we're safe--there's no way
>> we can be in the middle of a GC run at the same time we access the
>> string's data pointer. That's not the case with strings from a
>> different interpreter--we could be trying to get at the string data
>> while the GC is in the process of moving it around.
>
>Again, not only strings but all kind of containers using managed
>resources suffer from that problem.
>
>All that seems to imply, that we need two locks for shared access: one
>for protecting DOD/GC and a second for the PMC. Any container (including
>PerlStrings) would have to aquire the first (interpreter-global) lock,
>while a PerlNum only needs the second per PMC mutex. Ugly.

Yeah, it all potentially gets nasty.

Leopold Toetsch

unread,
Dec 24, 2003, 5:35:04 AM12/24/03
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:
> At 10:06 AM +0100 12/23/03, Leopold Toetsch wrote:
>>While its not too complicated to get from an PObj* to the arena its time
>>consuming (more or less, depending on ARENA_DOD_FLAGS), it seems simpler
>>to have an interpreter back-pointer in the (shared) PMC.

> Yep, you're right. Let's make it happen. We can use the synchronize
> pointer and hang a struct off of it with the owning interpreter and
> the PMC mutex, along with other things we need as we come across them.

Done. Including {UN,}LOCK_INTERPRETER(interp) macros to serialize
accessing different interpreters.

leo

Michael Scott

unread,
Dec 24, 2003, 3:30:15 PM12/24/03
to perl6-i...@perl.org

On 22 Dec 2003, at 23:59, Elizabeth Mattijsen wrote:
>
<snip>

> I think we need a change of mindset. Instead of seeing threaded
> programs as the special case, we would need to see that the single
> threaded program is the special case. See how many people use POE for
> event handling, and through what hoops (Perl) Tk needs to jump through
> to get proper event handling.

Reading this brought to mind a command-line Perl tool on NT that began
life as a quick hack and then grew and grew to the point where a quick
Perl Tk user interface would have made it into a proper app but
threading issues prevented it.

I wouldn't be surprised if many significant single threaded scripts
have remained so because they bumped against this ceiling.

Mike

Uri Guttman

unread,
Dec 24, 2003, 5:52:51 PM12/24/03
to Michael Scott, perl6-i...@perl.org
>>>>> "MS" == Michael Scott <michae...@mac.com> writes:

> Reading this brought to mind a command-line Perl tool on NT that began
> life as a quick hack and then grew and grew to the point where a quick
> Perl Tk user interface would have made it into a proper app but
> threading issues prevented it.

once you get into tk stuff, you have to think event loops over
threading. and for most basic apps you can do it either way. some
blocking (e.g simple file reading/writing) for an interactive tk app is
not a big issue. blocking only becomes a serious issue in server like
things where you want as much speed and throughput as possible. in a
interactive gui app, having the user wait a fraction of a second to do a
blocking operation is not a problem.

> I wouldn't be surprised if many significant single threaded scripts
> have remained so because they bumped against this ceiling.

again, threading is not the only answer there. if you want perl/tk, you
need to get into events and their pluses and minuses.

uri

--
Uri Guttman ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org

Leopold Toetsch

unread,
Dec 25, 2003, 12:10:18 PM12/25/03
to Dan Sugalski, perl6-i...@perl.org

Thinking a bit further about that issue /me thinks that we need:
1) one spare interpreter holding the shared resources[1]
2) on resource shortage this interpreter does DOD/GC else it
does nothing[2]
3) to accomplish 2) in a save way, all threads having a shared resource
must be suspended.[3]

Rational:

Looking at e.g string.c (but that could be list.c or hash.c too), we
have code like this:

FLOATVAL
string_to_num(const STRING *s)
...
const char *start = s->strstart; // (1)
const char *end = start + s->bufused; // (2)

This function is used by PerlString::get_integer() or ::get_number -
that is a *read* access of a PMCs data. Now when this PerlString is
shared between different PMCs, there is a chance that between (1) and
(2) the copying collector moves strstart to a different place, *if* the
owning thread does a GC run at that time: "start" and "end" are out of
sync - boom. We have such code all over the place, I don't see any
chance to rewrite that in a way, so that a GC run in the background
wouldn't harm.

We could of course lock the owning interpreter for *all* accesses, but
that seems more expensive than above "solution".

[1] basically the arena_base only and some more bits

[2] It would wait on a condition. If any thread allocates shared
resources, the spare interpreter would wake up, check if there is a
shortage in resources, and if yes suspend threads and run DOD/GC.

Considering how DOD runs with shared PMCs work is still more fun.

[3] They can't be suspended inmidst of an arbitrary operation (and
pthread doesn't even provide suspending) so they would be sent a suspend
event so that they are in a safe state in the run-loop, or better in the
event-handler opcode, called from there.

leo

Gordon Henriksen

unread,
Dec 30, 2003, 11:33:30 AM12/30/03
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

> Dan Sugalski wrote:
>
>> Leopold Toetsch wrote:
>>
>>> Again, not only strings but all kind of containers using managed
>>> resources suffer from that problem.
>>>
>>> All that seems to imply, that we need two locks for shared access: one
>>> for protecting DOD/GC and a second for the PMC. Any container
>>> (including
>>> PerlStrings) would have to aquire the first (interpreter-global) lock,
>>> while a PerlNum only needs the second per PMC mutex. Ugly.
>>
>> Yeah, it all potentially gets nasty.
>

> [...]


>
> [3] They can't be suspended inmidst of an arbitrary operation (and
> pthread doesn't even provide suspending) so they would be sent a
> suspend event so that they are in a safe state in the run-loop, or
> better in the event-handler opcode, called from there.

(Just got back from vacation and was reviewing this aging thread...)

Yes, yes! Stopping other threads when a rare condition occurs is a great
way to avoid penalizing a threaded program's common case with excessive
synchronization overhead. There are just too many things that can go
wrong otherwise; fine-grained locking is the alternative, and programs
will very, very rapidly find themselves spending 40% of their cycles
acquiring mutexes.

This is definitely the way to go to achieve blistering performance while
retaining dynamic capabilities. The work is already done to ensure that
while true { ; } will receive events in a timely fashion. Broadcasting
parrot events should be an excellent means of implementing inter-thread
synchronization.

Gordon Henriksen
mali...@mac.com

0 new messages