News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Amazed or Mortified?

Started by TBRANSO1, January 24, 2019, 03:44:48 PM

Previous topic - Next topic

TBRANSO1

Well, I just produced the most useless threading program.  I did it for practice.  I can't help but be amazed at the depth of the MASM32 library, but kind of scary that we can produce this with such ease in assembly.

VOILA!!!
For the beginners in the crowd... this is a program demonstrating Kernel threads, and how to modify global variables without synchronizations tools, like mutex or semaphores.  This uses the Local Thread Storage api and it locks down atomically access to the global variable so that each Thread gets it's own global for use and doesn't mess with the other threads use of their globals.


include \masm32\include\masm32rt.inc

ExitProcess PROTO :DWORD
CommonFunc PROTO
ThreadFunction PROTO
ExitError PROTO :LPSTR
ExitThread PROTO :LPSTR

.CONST
threadcount EQU 4

.DATA
tlsAllcFailedMsg DB "TlasAlloc failed!, error code: ", 0
dwCreateThdMsg DB "Create thread error, error code: ", 0
tlsValErrMsg DB "TlsGetValue error, error code: ", 0
tlsSetValErrMsg DB "TlsSetValue error, error code: ", 0

.DATA?
dwTlsIndex DWORD ?

.CODE
start:
call main
inkey
push 0
call ExitProcess

CommonFunc PROC
LOCAL lpvData:LPVOID

push dwTlsIndex
call TlsGetValue
mov lpvData, eax
.IF lpvData == 0
INVOKE GetLastError
.IF (!eax)
INVOKE ExitError, addr tlsValErrMsg
.ENDIF
.ENDIF

INVOKE GetCurrentThreadId

printf("Common: thread %d: lpvData = %lx\n", eax, lpvData)

INVOKE Sleep, 1000
CommonFunc ENDP

ThreadFunction PROC
LOCAL lpvData:LPVOID

push 0100h
push LPTR
call LocalAlloc
mov lpvData, eax
INVOKE TlsSetValue, dwTlsIndex, lpvData
.IF (!eax)
INVOKE ExitError, addr tlsSetValErrMsg
.ENDIF

call CommonFunc

INVOKE TlsGetValue, dwTlsIndex
.IF eax != 0
INVOKE LocalFree, lpvData
.ENDIF

xor eax, eax
ret
ThreadFunction ENDP

ExitError PROC lpszMessage:LPSTR
INVOKE GetLastError
printf("%s %d\n", lpszMessage, str$(eax))
push 0
call ExitProcess
ExitError ENDP

main PROC
LOCAL IDThread:DWORD
LOCAL hThread[threadcount]:HANDLE
LOCAL i:DWORD

INVOKE TlsAlloc
.IF dwTlsIndex == TLS_OUT_OF_INDEXES
INVOKE ExitError, addr tlsAllcFailedMsg
.ENDIF

mov i, 0
.WHILE i < threadcount
add i, 1
INVOKE CreateThread, 0, 0, addr ThreadFunction, 0, 0, addr IDThread
mov esi, i
mov [hThread+esi*4], eax
.IF eax == 0
INVOKE ExitError, addr dwCreateThdMsg
.ENDIF
.ENDW

INVOKE WaitForMultipleObjects, 4, addr hThread, TRUE, -1

INVOKE TlsFree, dwTlsIndex

xor eax, eax
ret
main ENDP
end start


8)

hutch--

After a while you will get used to it, you can do truly wicked things with MASM.  :biggrin:

zedd151

I never did understand TheadLocalStorage really, but this thread (pardon the pun) sparked my interest in doing a little more research, to better my understanding of how it works.

AK_AK

Feel the power, it puts a 30-30 to shame !  :badgrin:

i was amazed when i first learned of TLS let alone how it could be used, there is so much potential there.
just remember, the stronger you are the greater strives you should take to show your gentle side.

TBRANSO1

Jeesh, I didn't know that Thread Local Storage would turn so many people on.  :shock:

jj2007

There is a simple reason: Our algos are so blazing fast that we never need multiple threads. And in the rare cases we need TLS, we just roll our own  8)

hutch--

I know the environment that TLS was designed for but I am yet to see the reason to use it with assembler code in Windows. Any memory you allocate in any thread you allocate it in has a separate handle so there is no chance of overlap (this is what protected mode is for). As long as you do not try to use memory common to all threads IE: GLOBAL allocation, I have yet to see the gain of TLS.

Even if you have some reason to use GLOBAL memory, there are methods of access control so that two or more threads don't clash in their memory access.

TBRANSO1

Hutch,

Since I got your attention...

If I wanted to mostly the crt libraries, which is the least amount of includes to use?  instead of the more general masm32rt.inc

I ask b/c it seems if I don't use the general blanket masm32rt.inc, I get crt link errors all over the place.

If you understand what I am asking?

hutch--

I don't know exactly what you are doing but if you have a look at the MSVCRT.INC file in MASM32, it prefixes "crt__" to the list of function names. You will get errors if you try to use the original MSVCRT function names. The problem is a naming range clash so the prefix solved the problem. What I don't know is if you need prototypes for API calls for MSVCRT.

HSE

Most libraries are very modular. If you don't use a function, that function is not added to your program.
Prototypes are already declared when masm32rt.inc is included.
Equations in Assembly: SmplMath

AK_AK

#10
i think i is somewhere in the MSDN but i recall the TLS being described as a way to [Xpass dataX] make data commonly available
{X with a thread along with the call for execution.X] among threads of a parent process
a backdoor of a sort that allows threads to [Xpass information to a separate thread.X] share a common pool

https://docs.microsoft.com/en-us/windows/desktop/ProcThread/thread-local-storage

here is a gem, if you are using multiple threads, and they must access tha same data set, there is less overhead than synching threads to pass data.
the threads use a common "structure" and can read write modify with no burden of lock synch release hueristics, thus faster.

The TLS comes in when a data structure can be used locally in the thread, and results or changes can be reflected ASYNCHRONOUSLY in the common data structure


there is a way that a thread could be created under the parent process of a "target" thread and be used to manipulate the data.
this is what i found intriguing about TLS, and gave me concern about the potential for abuse.

more about TLS here :

https://software.intel.com/en-us/articles/use-thread-local-storage-to-reduce-synchronization

TBRANSO1

Quote from: AK_AK on January 27, 2019, 08:29:11 AM
i think i is somewhere in the MSDN but i recall the TLS being described as a way to [Xpass dataX] make data commonly available
{X with a thread along with the call for execution.X] among threads of a parent process
a backdoor of a sort that allows threads to [Xpass information to a separate thread.X] share a common pool

Isn't that one hell of a definition?  :dazzled:

AK_AK

i edited the comment but wanted to be fair and included my mistakes so [XblahblahblahX] is junk,

lets try this: if you have a bunch of data and it doesnt matter what time the data is changed, or if the changes are in proper order, then you can use TLS to share data . that means only the change in data is important, and threads using it are communicating by way of a postit note mechanism.

otherwise multithreading will need to lock the data, change it then unlock it so other threads can access the data.

a real world example, would be:  interest calculations on multiple bank accounts, or stock picks in a real time stock trading application.

TBRANSO1

Quote from: AK_AK on January 27, 2019, 11:23:46 AM
lets try this: if you have a bunch of data and it doesn't matter what time the data is changed, or if the changes are in proper order, then you can use TLS to share data . that means only the change in data is important, and threads using it are communicating by way of a post-it note mechanism.

a real world example, would be:  interest calculations on multiple bank accounts, or stock picks in a real time stock trading application.

I like the post-it note explanation.  :icon14:

hutch--

There are a few tricks when creating multiple threads with the same data, With CreateThread() you pass a structure full of whatever you need the thread to have, the caller then runs a spinlock that waits for a reply from the newly created thread and when the reply is received, it the creates the next one. Without this the structure is overwritten by the following thread creation.