multithreading in Asm

  • Follow


Hi all,

I've never been very clear as to how multithreading is
implemented in high level languages, I guess because
I never untar'd pthreads to take a look, but that's
beside the point. My question now is, if I am not
interested in using a C library to do multithreading,
what are my options in assembly language?
And I want it to be portable to other x86 OSes,
so calling Win32's CreateThread would be undesirable.

Thanks.
0
Reply questioner_x3 (5) 12/31/2009 11:11:05 PM

"Qyz" <questioner_x@MUNGED.microcosmotalk.com> wrote in message 
news:4b3d2f89$0$5121$9a6e19ea@unlimited.newshosting.com...
>
> Hi all,
>
> I've never been very clear as to how multithreading is
> implemented in high level languages, I guess because

Multi-threading cannot be implemented in HLLs.  It is a feature of the 
Operating System.

> I never untar'd pthreads to take a look, but that's
> beside the point. My question now is, if I am not
> interested in using a C library to do multithreading,
> what are my options in assembly language?

Assembly Language has no instructions for it.  The CPU does not understand 
threading concepts.  Therefore, there are absolutely no multi-threading 
options available to you.

> And I want it to be portable to other x86 OSes,
> so calling Win32's CreateThread would be undesirable.
>

You must use 'CreateThread' because Windows does not provide any other 
facility for multi-threading.

Nathan.


0
Reply Nathan 1/1/2010 1:00:09 AM


On 31 Dec 2009, 23:11, Qyz <questione...@MUNGED.microcosmotalk.com>
wrote:
> Hi all,
>
> I've never been very clear as to how multithreading is
> implemented in high level languages, I guess because
> I never untar'd pthreads to take a look, but that's
> beside the point. My question now is, if I am not
> interested in using a C library to do multithreading,
> what are my options in assembly language?
> And I want it to be portable to other x86 OSes,
> so calling Win32's CreateThread would be undesirable.

I've not tried it but you may find posix threads available for various
operating systems.

James
0
Reply James 1/1/2010 1:26:45 AM

I don't disagree with anything you say, Nathan, but let me pick a few 
nits in hopes of teasing out a slightly better answer for Qyz. I don't 
know the answer, but I admire the question! :)

Nathan Baker wrote:
> "Qyz" <questioner_x@MUNGED.microcosmotalk.com> wrote in message 
> news:4b3d2f89$0$5121$9a6e19ea@unlimited.newshosting.com...
>> Hi all,
>>
>> I've never been very clear as to how multithreading is
>> implemented in high level languages, I guess because
> 
> Multi-threading cannot be implemented in HLLs.

But it is...

> It is a feature of the 
> Operating System.

Yeah. Specifically, I suppose we need to talk to the "scheduler"???

>> I never untar'd pthreads to take a look, but that's
>> beside the point.

Me, neither... but I think somebody's going to have to!

>> My question now is, if I am not
>> interested in using a C library to do multithreading,
>> what are my options in assembly language?
> 
> Assembly Language has no instructions for it.

You mean the CPU can do something that can't be expressed in asm? I 
don't believe it! I think(?) it would be more correct to say that we use 
"ordinary instructions"... in Linux, int 80h... to discuss with the OS 
what we have in mind. What do we say to the OS? Aye, there's the rub!!!

> The CPU does not understand 
> threading concepts.

Okay, but what about "hyperthreading"? Apparently, some CPUs have the 
capability, and some don't(?). I'm not sure where/how this fits in with 
plain "threading". I suspect we "say the same thing" to the OS, and the 
OS determines whether we've got "hyperthreading" available or not... and 
perhaps whether or not to use it, if so.

> Therefore, there are absolutely no multi-threading 
> options available to you.

Well surely he can call "libpthread.so" or "pthread32.dll" or whatever, 
same as from a hll. I don't think there are any "special" options open 
to us 'cause we're doin' it in asm... Unless you're writing your own OS, 
and writing the scheduler... in which case you'd still be using 
"ordinary" instructions, I suspect.

>> And I want it to be portable to other x86 OSes,

Good luck with that one! James mentions "POSIX". Calling a "posix 
compliant library" might be your best bet.

>> so calling Win32's CreateThread would be undesirable.

Wouldn't work at all for me! :)

> You must use 'CreateThread' because Windows does not provide any other 
> facility for multi-threading.

Well, if you're gonna do it *that* way, maybe... :)

I've got a rudimentary "test" program that just calls libpthread.so's 
pthread_create, four times. Says "Creating thread N", and calls 
pthread_create, in a loop. In each case the thread says "Hello from 
thread N" (N passed as a parameter). In most cases, it says:

creating thread 0
Hello from thread 0
creating thread 1
Hello from thread 1
creating thread 2
Hello from thread 2
creating thread 3
Hello from thread 3
creating thread 4
Hello from thread 4

In other words, each thread is being executed as soon as it's created. 
But sometimes...

creating thread 0
creating thread 1
Hello from thread 0
creating thread 2
creating thread 3
Hello from thread 1
Hello from thread 3
creating thread 4
Hello from thread 4
Hello from thread 2

.... or in other orders... I take this as evidence that it's "working"...

Running this in "strace", I can see the system calls that the library 
uses. It seems to be sys_clone that does the business, but there's a 
whole lot of stuff around it that I don't comprehend!

If I can get past the library and do it with just int 80h - definitely 
possible, whether *I* can figure it out or not - it'll still just be a 
conversation with the OS. "Ask the scheduler to put this on its 
play-list, please."

So if your API is CreateThread... that's the way you do it...

Best,
Frank
0
Reply Frank 1/1/2010 9:55:09 AM


Frank answered Nathan:

> I don't disagree with anything you say, Nathan, but let me pick a few nits 
> in hopes of teasing out a slightly better answer for Qyz. I don't know the 
> answer, but I admire the question! :)

:)
....
>> Multi-threading cannot be implemented in HLLs.
> But it is...

Beside distributed jobs to several CPUs and BusMaster-hardware,
I'd see programmable software 'multi-threading' as 'multiplexed'.

Either chained code elements or HW-event(timer) driven switches
can be implemented in ASM and HLL as well.

>> It is a feature of the Operating System.
> Yeah. Specifically, I suppose we need to talk to the "scheduler"???

Dunno internals on windoze/Linux, but they both seem to (ab)use
hw-resources like several CPU-cores by their own rules ...

....
>>> My question now is, if I am not
>>> interested in using a C library to do multithreading,
>>> what are my options in assembly language?

>> Assembly Language has no instructions for it.
> You mean the CPU can do something that can't be expressed in asm?

There are several things like MSRs, chipset-configuration and
busmaster controls which could of course be expressed in ASM,
but I'm afraid compilers wont support EFER,MTRR/PAT,SYSCFG,PDRT,...

> I don't believe it! I think(?) it would be more correct to say that we
> use "ordinary instructions"... in Linux, int 80h... to discuss with the
> OS what we have in mind. What do we say to the OS? Aye, there's the rub!!!

Yeah, unless you roll your own, the OS is the limiting factor.

>> The CPU does not understand threading concepts.

> Okay, but what about "hyperthreading"? Apparently, some CPUs have the 
> capability, and some don't(?). I'm not sure where/how this fits in with 
> plain "threading". I suspect we "say the same thing" to the OS, and the OS 
> determines whether we've got "hyperthreading" available or not... and 
> perhaps whether or not to use it, if so.

Isn't Hyperthreading mentioned as hardware-link (peripheral/chipset-devices
can communicate and bypass the main bus) ?

>> Therefore, there are absolutely no multi-threading options available to 
>> you.

> Well surely he can call "libpthread.so" or "pthread32.dll" or whatever, 
> same as from a hll. I don't think there are any "special" options open to 
> us 'cause we're doin' it in asm... Unless you're writing your own OS, and 
> writing the scheduler... in which case you'd still be using "ordinary" 
> instructions, I suspect.

With ASM we can access everthing, as long the OS allow it.
I'm not sure about OS-supported multi-threads will always show
desired behaviour, often seen: mouse responds delayed by 'seconds!'.

....
__
wolfgang
btw: Happy New Year!
 


0
Reply wolfgang 1/1/2010 12:47:55 PM

On Dec 31 2009, 8:00 pm, "Nathan Baker"
<nathancba...@MUNGED.microcosmotalk.com> wrote:

> You must use 'CreateThread' because Windows does not provide any other
> facility for multi-threading.

I recall hearing years ago that, before OSes supported
multithreading, it was being done purely in user-land and
somewhat successfully. One could say therefore it's possible
to re-achieve that success in asm in an OS-independent way
today, however since OSes support it now, it's obviously
better to use the OS facility as that will provide access
to multiple cores, hyperthreading when present, etc.
0
Reply Qyz 1/1/2010 4:11:02 PM

On Jan 1, 11:11=A0am, Qyz <questione...@MUNGED.microcosmotalk.com>
wrote:
> On Dec 31 2009, 8:00 pm, "Nathan Baker"
>
> <nathancba...@MUNGED.microcosmotalk.com> wrote:
> > You must use 'CreateThread' because Windows does not provide any other
> > facility for multi-threading.
>
> I recall hearing years ago that, before OSes supported
> multithreading, it was being done purely in user-land and
> somewhat successfully. One could say therefore it's possible
> to re-achieve that success in asm in an OS-independent way
> today, however since OSes support it now, it's obviously
> better to use the OS facility as that will provide access
> to multiple cores, hyperthreading when present, etc.

You are thinking of co-routines, fibers, "protothreads", and their
kin.  See:  http://groups.google.com/group/comp.lang.asm.x86/browse_thread/=
thread/0627d72bd1f6ca64?hl=3Den#

Nathan.
0
Reply Nathan 1/1/2010 6:08:18 PM

On Jan 1, 4:55=A0am, Frank Kotler <fbkot...@MUNGED.microcosmotalk.com>
wrote:
>
> Nathan Baker wrote:
> > "Qyz" <questione...@MUNGED.microcosmotalk.com> wrote in message
> >news:4b3d2f89$0$5121$9a6e19ea@unlimited.newshosting.com...
> >> Hi all,
>
> >> I've never been very clear as to how multithreading is
> >> implemented in high level languages, I guess because
>
> > Multi-threading cannot be implemented in HLLs.
>
> But it is...
>

Perhaps it is!?  I suspect that it depends on exactly what one is
talking about when the "HLL" acronym is being tossed into the
air.  :)  We ASMers might be accustomed to labeling C (and C++) as an
HLL.  But, perhaps, the OP might think of C as a low-level language.
I suppose that it is possible to write an Operating System (or what
might pass as an OS for argument's sake) in one of today's popular
HLLs { Java, Perl, Python, etc. }, but it isn't a typical, practical
practice.  Hence, "for all intents and purposes", 'thread' support is
not usually *implemented* in HLLs.  For instance, most of the MS-
Windows API functions are implemented in ASM/C/C++ {perhaps some of
the more modern functions were written in C# and therefore rely on
the .NET VM, but that's another issue}.  Heck, if someone happens to
know where there is some PHP source-code that implements multi-
threading services, please feel free to show us.  :)

Nathan.
0
Reply Nathan 1/1/2010 6:08:49 PM

"Qyz" <questioner_x@MUNGED.microcosmotalk.com> wrote in message
news:4b3d2f89$0$5121$9a6e19ea@unlimited.newshosting.com...
>
> I've never been very clear as to how multithreading is
> implemented in high level languages, I guess because
> I never untar'd pthreads to take a look, but that's
> beside the point.

Let's first attempt to explain how "threading" is typically done in C
threading libraries.  I'm saying attempt because I only have a rough
understanding of the mechanism.  Usually, the threading library makes use of
C's setjmp() and longjmp().  Basically, setjmp() and longjmp() are supposed
to save and restore the entire "C context".  That means whatever is needed
to return execution to the exact same prior state.  Usually, what this means
is that setjmp() and longjmp() save and restore all or most of the cpu
registers.  They don't save any stack data.  There's an array created for
this purpose of type jmp_buf.  Since esp and ebp are typically used to setup
stackframes for C procedures (cdecl calling convention), saving and
restoring the registers also resets or rolls back the stack to a specific
stackframe.  However, the returned to procedure's local variables are
created after the stackframe, so C doesn't require them to be preserved.
That would require saving some of the information on the stack.  In normal C
code, lonjmp() returns to where setjmp() was called, restoring the prior
execution context, and returns a return value.  The return value is commonly
passed to a switch() to execute different code for each return value.  I.e.,
setjmp() could be used as the centralized starting point of a switch() based
task scheduler, but my understanding is things are done differently as
follows.

In theory, by using setjmp() and longjmp() to save/restore registers,
multiple jmp_buf's - one for each task, an interrupt and return method,
e.g., raies() and signal(), and maybe some assembly, you can switch between
different pieces of executing code.  Typically, when a signal is raised, an
interrupt handler function is called.  Ideally, a timer or scheduler is
generating the signal periodically.  The interrupt handler function normally
returns to where the interrupt was generated, but this can be changed.
longjmp() is called with the jmp_buf for the next thread instead of
returning from the interrupt handler function.  Execution will be transfered
to the next thread.  Somewhere, setjmp() must be called to init each thread,
and called again when a thread is interrupted to save the current context
(or set of registers).  I'm not clear on the details of when the "2nd
setjmp()" occurs.  However, there is an issue with using C for threading.
Each thread needs it's own stack and C typiccally is implemented with a
single stack.  I.e., you can't use C's stack safely.  To make sure that each
thread has it's own stack, requires allocating and setting up stacks, and
modifying registers in the jump buffer, specifically esp and ebp, to point
to that thread's stack.  Technically, I think it may be possible to do this
entirely in C.  But, every implementation I recall looking at required some
assembly to get things "just right".  It's likely the 2nd call to setjmp() -
to save the registers when interrupted - must be done in assembly.

> My question now is, if I am not
> interested in using a C library to do multithreading,
> what are my options in assembly language?

Options?  Do you mean like: Write your own?  This is an assembly
newsgroup...

I'm _assuming_ you'll need to do something similar to the following:

1) init thread context with initial register values
2) allocate thread stack
3) set stack registers in thread context to point to stack
4) repeat 1-3 for all threads
5) install interrupt or central yield routine
6) call a random thread
7) when interrupt routine is called or thread calls yield routine:
7a) save all registers for current thread in it's context
7b) load registers with context for next thread
7c) return from interrupt or yield to switch to new thread
8) new thread is executing - until step 7 re-occurs

"thread context" is just storage space for all the registers you'll be
saving and restoring per thread.

For 16-bit or 32-bit code, you could look at PUSHA and PUSHF to save all
registers and flags onto a stack, respectively.  MOV or PUSH with POP "mem"
can be used to save out registers.  Or, you could look at STOSD and XCHG EAX
to save out registers. Pushing them to the stack (PUSHA), then copying them
from the stack to memory (REP MOVS), and fixing the stack pointer (LEA ESP)
is another option.  etc.

> And I want it to be portable to other x86 OSes,
> so calling Win32's CreateThread would be undesirable.
>

x86 supports 16-bit, 32-bit, and 64-bit code.  Have you choosen a specific
size?  I.e., do you plan to have all three in order to be "portable to other
x86 OSes"?

Portable to other x86 OSes implies common memory allocation method of some
sort or other.  I doubt anything of the sort exists for assembly.  So, you'd
have to make the code adapt to the memory allocation method of each OS -
which means you need a common method of determine what OS you're on...
Catch-22?  I.e., code to determine what OS you're on is likely OS specific.
You'd need some type of checks which work on each specific OS *AND* which
fail passively if on the incorrect OS.  Or, I guess you could use static
data compiled into the executable as stack space, but you don't know how
much space or how many threads...  The closest thing for a HLL like C is
it's internal stack, but manipulating that will lead to problems.


Rod Pemberton


0
Reply Rod 1/1/2010 7:40:23 PM

On 31 Dec 2009, 23:11, Qyz <questione...@MUNGED.microcosmotalk.com>
wrote:
> My question now is, if I am not
> interested in using a C library to do multithreading,
> what are my options in assembly language?

I was doing multithreading in Z80 code way back in the 1970s!  Crude
multithreading is actually quite straightforward to code in
assembler.  All you need is a regular timer interrupt (say at around
100 Hz).  In the interrupt service routine you do the following:

1.  Save the CPU's context to the stack (for the main registers that's
just a 'pusha')
2.  Save the stack pointer in memory (one location per thread is
required).
3.  Load the stack pointer from the saved value for the 'next' thread.
4.  Restore the CPU's context from the stack (e.g. 'popa' for the main
registers).
5.  Return from the interrupt.

Of course each thread needs its own stack, which is set up when the
thread is created.

That's the simplest possible kind of multithreading (each thread is
given the same time slice, in strict rotation), but it works.  If a
thread wants to release the CPU prematurely it basically just calls
the same routine that the timer interrupt activates, handing control
to the next thread in the list.

Richard.
http://www.rtrussell.co.uk/
To reply by email change 'news' to my forename.
0
Reply Richard 1/2/2010 12:48:33 AM


"Nathan Baker" <nathancbaker@MUNGED.microcosmotalk.com> wrote in message 
news:4b3d4919$0$4976$9a6e19ea@unlimited.newshosting.com...
>
> "Qyz" <questioner_x@MUNGED.microcosmotalk.com> wrote in message
> news:4b3d2f89$0$5121$9a6e19ea@unlimited.newshosting.com...
>>
>> Hi all,
>>
>> I've never been very clear as to how multithreading is
>> implemented in high level languages, I guess because
>
> Multi-threading cannot be implemented in HLLs.  It is a feature of the
> Operating System.
>

this is more true of processes than of threads...

the OS handles threads, but is not necessary to use it to have threads...

more so, in the case of many HLL's, it is not even really necessary that 
there be multiple OS threads to implement multiple HLL threads. this could 
be the case either with an interpreter (which could jump between interpreter 
contexts), or a language VM implementing control-flow in terms of 
light-weight continuations (where control flow is driven by hoping between 
continuations rather than by using sequential instructions, stacks, and 
jumps).

granted, neither is the case with more typical HLL's, such as C (or, at 
least, if running directly on the CPU...).


>> I never untar'd pthreads to take a look, but that's
>> beside the point. My question now is, if I am not
>> interested in using a C library to do multithreading,
>> what are my options in assembly language?
>
> Assembly Language has no instructions for it.  The CPU does not understand
> threading concepts.  Therefore, there are absolutely no multi-threading
> options available to you.
>

again, I disagree...

however, what one can do to implement it would be nasty and not play well 
with the OS, so it can be more said that implementing multithreading 
manually would be a rather bad idea...

FFS, one can do multi-threading in MS-DOS if they feel so pleased, but one 
also has to be careful as doing this poorly can also break the OS...

nothing stops multi-threading on an 8088 either, FWIW...


if it does not require privledged instructions, it can be done.
threading, FWIW, does not require privledged instructions.


>> And I want it to be portable to other x86 OSes,
>> so calling Win32's CreateThread would be undesirable.
>>
>
> You must use 'CreateThread' because Windows does not provide any other
> facility for multi-threading.
>

sort of...

as I see it, one is "very well advised" to use CreateThread...


but, if one wants to use timer events and implement their own localized 
context switching, little exists to prevent it, since it can be done without 
requiring privledged instructions...

now, if one wants cooperative threads, this is easy (no special tricks 
required apart from localized context switching). preemptive threading is a 
little nastier, and personally I would somewhat advise against this (and, 
more so, the OS can do a better job, since it has access to much more of the 
CPU than does a userspace app).

I will say this much:
pusha, popa, fxsave, fxrstor.
the rest is stack swapping, ...

however, I will not say much more, and will say that this is still an 
ill-advised strategy.

this is mostly because the OS does a lot "behind the scenes", and doing 
ones' own threading will generally violate many basic sanity assumptions 
made by the OS (as well as setting things up such that the wrong event at 
the wrong time will very seriously mess up the app, such as the OS doing its 
own context-switching, or calling an event handler, right in the middle of 
an app-local context switch, ...).

similarly, pulling it off would still likely result in digging around in a 
lot of OS-specific stuff...



0
Reply BGB 1/2/2010 1:59:48 AM

10 Replies
277 Views

(page loaded in 0.06 seconds)

Similiar Articles:












7/22/2012 3:54:32 PM


Reply: