Let's take a simple case, I want to set a lock (based on the assembly
in PowerPC book):
[snip]
All you're doing there is an atomic increment! If you want to "take"
a lock, first test the current lock value, then either spin or block
if it's already locked. Are you in the kernel or user space? BTW,
you can use addic. which also works with R0.
I removed all the testing because this simple case isn't working!
Something very wrong is going on (see below).It looks like it should be
working but just isn't. Is this not working because of prefetching of
the data (which is why isync is there, using sync doesn't change
anything).
register unsigned char _t; // so I don't have to worry about safe
__asm__ __volatile__
(
"\n"
"_lock_1:\n\t"
"lwarx %1,0,%0 \n\t" // load lock and reserve
"addi %1,0,1 \n\t" // set lock (1 is locked)
"stwcx. %1,0,%0 \n\t" // try to set lock
"bne- _lock_1 \n\t" // loop if lost reservation
"isync \n\t" // import barrier
: // no output
: "r" (__count), "r" (_t) // input
: "cc", "memory"
);
}
volatile unsigned char *testB;
int main(void) {
testB = (unsigned char *) malloc(sizeof(unsigned char));
*testB = 0;
printf("testB is %d and stored at %d.\n Now locking.\n", *testB,
(int) testB);
_lock_(testB);
printf("testB is now %d\n", *testB);
return 0;
}
generates this (gcc -O inline_test.c -S). My comments on the assembly
might be wrong;
[snip]
mflr r31 // save return address from link register into r31
li r28,0 // for use in _lock_?
// get the address of the variable testB, which
// stores the address of the data
// 32bit number so must load in two steps
addis r29,r31,ha16(L_testB$non_lazy_ptr-"L00000000001$pb")
lwz r29,lo16(L_testB$non_lazy_ptr-"L00000000001$pb")(r29)
li r3,1 // size to allocate (arg 0)
bl L_malloc$stub // call malloc, returns address in r3
mr r5,r3 // move r3 into r5 (arg 2 for printf below)
stw r3,0(r29) // store word (32-bits) r3 into .data section
(L_testB) from r3
// I guess this is the address top the space requested
li r0,0 // set value to 0 in r0
stb r0,0(r3) // store 0 into the returned address
// note that the L_testB has the address loaded
addis r3,r31,ha16(LC0-"L00000000001$pb") // load string address for
arg 0
la r3,lo16(LC0-"L00000000001$pb")(r3)
lbz r4,0(r5) // load byte pointed to by r5 (which is testB's
address) in arg 1(r4)
bl L_printf$stub // print "testB is 0 and stored at 3146048\n Now
locking."
lwz r0,0(r29) // load r0 with the address stored in r29 (testB's)
_lock_1:
lwarx r28,0,r0 // load lock from address in r0 into r28
and reserve it
addi r28,0,1 // also tried li r28, 1 (still doesn't
work)
stwcx. r28,0,r0 // try to save set lock stored in r28 to
address pointed to by r0
bne- _lock_1
isync // import barrier, should clear pre-fetched
data/instructions
lwz r2,0(r29) // get address from address pointed to by
r29 (L_testB)
addis r3,r31,ha16(LC1-"L00000000001$pb") // load string address
for arg 0
la r3,lo16(LC1-"L00000000001$pb")(r3)
lbz r4,0(r2) // get byte pointed to by the value in r2
into r4 (arg 1)
bl L_printf$stub // prints "testB is now 0" -- should be
"testB is now 1"!