0

I had no problems with the shipped version of MinGW that comes with CodeBlocks 12.11. But now I tried to compile SyncSys. Compiling enet was no problem but compiling SyncSys itself with gcc/MinGW brings the errors, that I can't use the function _InterlockedOr8 because it is not declared. Research lead to the fact that _InterlockedOr8 is defined in intrin.h. intrin.h is not included and I searched for the equivalent for it on MinGW/gcc: x86intrin.h. But this still does not work. InterlockedOr8 would be the "real" function to call but this is could not be found either by the compiler although winbase.h and windows.h are included.

While researching this problem there where very few hits I could not learn from. How can I fix this?

Community
  • 1
  • 1
Joshua Behrens
  • 818
  • 13
  • 23

1 Answers1

1

_InterlockedOr8 is an intrinsic compiler function unique to the Microsoft compiler - meaning that the compiler automatically inlines an implementation into the code instead of linking with a library. <intr.h> is a header file distributed with Visual Studio, separate from the Windows SDK.

If you can't switch to Visual Studio (free download, btw), then you could define your own replacement version of this function:

void InterlockedOr8(char* dst, char src)
{
    __asm
    {
        mov eax, dst       ; EAX = dst
        mov cl, src        ; ECX = src
        lock or [eax], cl  ; *dst = src | *dst; // this is the actual interlocked-or op
    }
}

Notice that this function differs from _InterlockedOr8 in the fact that it doesn't return the original value of *dst. The implementation gets a more complicated if you need the return value. I took a quick look at SyncSys source. The two places that need that function don't need the return value. So all you have to do is convert the above code to use the gcc style of inline assembly.

Update

Here's a version that correctly returns the original value within the destination address before the OR operation. It could probably use a little code review scrutiny...

char MyInterlockedOr8(char* dst, char src)
{
    char result = 0;
    const size_t ptr_size = sizeof(dst);

    _asm
    {
        mov esi, dst    ; esi = dst
        mov cl, src     ; cl = src // keep "src" cached in a register
        mov al, [esi]   ; al = *dst
start:
        mov bl, cl      ; bl = src
        or bl, al       ; bl = src | *dst

        lock cmpxchg [esi], bl;   // if (*dst == eax) { *dst=bl ;} else {al = *dst};
        jne start

        mov result, al  ; result = al
    }

    return result;
}
selbie
  • 100,020
  • 15
  • 103
  • 173
  • I could switch to VS, I have VS already installed but I do not like the IDE and if I set the compiler in CodeBlocks to MSVC10 I have no debugger and cl.exe always throws D8003-Errors. I never had a look at assembler so I have no idea what is going on in your code so it would be cool if you can add some hints/comments and thanks for your help. – Joshua Behrens Jan 05 '14 at 08:21
  • I also had a look at the code, you are right that it does not care about the return value but _InterlockedAnd8 have to return the right value because that is used. I just guessed that the code for _InterlockedAnd8 must be: void _InterlockedAnd8( volatile char* dst, char src ) { asm( "mov eax, dst;mov cl, src; lock and [eax], cl;" ); } Am I right? – Joshua Behrens Jan 05 '14 at 08:35
  • More or less. But if the code actually makes use of the return value from InterlockedOr8 (which is the value pointed to by dst before the swap), the generated assembly code becomes a bit more and makes uses of an interlocked-compare-exchange call. – selbie Jan 05 '14 at 08:49
  • Can't I just copy the value of *dst into an other variable and then return this variable? Sth like: char _InterlockedAnd8( volatile char* dst, char src ) { char ret( *dst ); asm( "mov eax, dst;mov cl, src; lock and [eax], cl;" ); return ret; } ? – Joshua Behrens Jan 05 '14 at 09:10
  • @JoshuaBehrens - As you have it, if the contents of dst got changed by another thread in between your assignment of "ret" and the "or" opcode, then the return value would not be correct. The volatile keyword at best will only make the "dst" variable thread safe, not the address that it refers to. – selbie Jan 05 '14 at 09:23
  • @JoshuaBehrens - The whole point of these "interlocked" calls is to do variable assignments in a thread-safe manner. Personally, I try to avoid these "atomocally locked" compare/exchange functions and lean more towards using locks (mutexes, critical sections) around whole blocks of code. Unless you really know what you are doing, the possibility of race conditions is very high when trying to do lockless multithreaded programming and the performance benefits are usually negligible. – selbie Jan 05 '14 at 09:23
  • Why does your [at]name: work and mine not in front of my message? Never mind. Yeah I know why it is done, but I do not know how it is done in these functions. If I work multitreaded then I m using locks too. So I could also just replace this code with my favorite threading library's un/lock function/guard function and it would be ok too? If this extends more and more I will use the chat. – Joshua Behrens Jan 05 '14 at 09:42
  • @JoshuaBehrens - You could use a lock, and that was almost my original suggestion. But if there are other parts of the SyncSys code touching those same protected variables with other interlocked functions besides InterlockedOr8, then those code paths would have to be converted to use the same lock. And that starts to become messy. – selbie Jan 05 '14 at 09:48
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/44546/discussion-between-joshuabehrens-and-selbie) – Joshua Behrens Jan 05 '14 at 10:03
  • @JoshuaBehrens - updated again and in the chat discussion. I got esi and esp confused. – selbie Jan 07 '14 at 05:20
  • Added an entry in our chat. In your updated version is the ptr_size, but it is unused? Do one need this? – Joshua Behrens Jan 07 '14 at 06:55
  • @JoshuaBehrens - updated again after testing on Linux. Your version had the input and output parameters of the assembly box in reverse order. See the chat discussion. – selbie Jan 07 '14 at 09:13