This is wrong. lwarx/stwcx work on word-sized entities. You are only
allocating a byte.
D'Oh!!! I feel like an idiot.
Okay, here is my finished code which now works. I think I got the
branch predictions correctly (bne- predicts it to fail, or fall
through). All of this was to replace a sync instruction used to insure
a lock (export barrier). I've rewrote it in asm using lwarx/stwcx as an
atomic-set. This works on my SP machine, but I don't know how to spawn
a new process that uses the shared memory.
#include <stdio.h>
typedef unsigned int slock_t;
/**
* Test-And-Set, for postgreSQL
*
* Based on an example from (E-book for embedded)
* Enhanced PowerPC Architecture Book Appendix C.1.2
*
* and from PowerPC Virtual Environment Architecture, Book II
* Appendix B.2
*/
static inline int _tas_(volatile slock_t *lock) {
register slock_t _t; // so I don't have to worry about safe Regs
int _res;
__asm__ __volatile__
(
"\n\t"
"li %0,0 \n\t" // default returns 0 as success
"lwarx %2,0,%1 \n\t" // load lock and reserve
"cmpwi %2,0 \n\t" // compare to 0 (unlocked) */
"bne- 1f \n\t" // locked, go to 1 (- predicts fall through)
"addi %2,0,1 \n\t" // set lock (1 is locked)
"stwcx. %2,0,%1 \n\t" // try to set lock
"beq+ 2f \n" // success if eq
"1:\n\t"
"stwcx. %2,0,%1 \n\t" // locked, but have to clear reserve (PPC
970s)
"li %0, 1 \n" // return 1 for failure
"2:\n\t"
"isync \n\t" // import barrier
: "=&r" (_res) // output, inforce different registers
: "r" (lock), "r" (_t) // input
: "cc", "memory"
);
return _res;
}
/**
* An atomic-unlock, this is to replace a sync, followed by unlocking.
*/
static inline void _unlock_(volatile slock_t *lock) {
register unsigned char _t;
__asm__ __volatile__
(
"\n"
"_unlock_1:\n\t"
"lwarx %1,0,%0 \n\t" // load lock and reserve
"addi %1,0,0 \n\t" // unset lock (0 is unlocked)
"stwcx. %1,0,%0 \n\t" // try to store lock state
"bne- _unlock_1 \n\t" // loop if lost reservation
"isync \n" // import barrier
:
: "r" (lock), "r" (_t)
: "cc", "memory"
);
}
volatile slock_t *testB;
int main(void) {
testB = (slock_t *) malloc(sizeof(slock_t));
*testB = 0;
printf("testB is %d.\nNow locking.\n", *testB, (int) testB);
if(_tas_(testB)) {
printf("unable to lock testB!\n");
// do/while - wait a bit and try again
} else {
printf("locked testB!\n");
};
printf("Now unlocking..\n");
_unlock_(testB);
printf("testB is now %d\n. Trying to get stuck.\n", *testB);
// now block and get stuck
if(!_tas_(testB)) {
do {
} while (_tas_(testB));
} else {
printf("Couldn't lock!\n");
}
return 0;
}