This is the mail archive of the
cygwin-patches
mailing list for the Cygwin project.
Re: [PATCH?] Separate pthread patches, #2 take 3
Christopher Faylor wrote:
> I thought that, given your last message to cygwin-developers, you were
> going to go off and figure out the best of four implementations. Is this
> the result of that investigation?
Once I discarded the ones that weren't quite right because they included a
setz/sete instruction (bsd and boehm), I was left with the ones in the
attached testcase. The only version I hadn't tested yet is the linux-derived one:
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
#define LOCK_PREFIX " lock "
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long newv)
{
unsigned long prev;
__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
: "=a"(prev)
: "q"(newv), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
}
extern __inline__ long
ilockcmpexch (volatile long *t, long v, long c)
{
return __cmpxchg (t, c, v);
}
This actually produces the same assembly as my version:
L14:
movl __ZN13pthread_mutex7mutexesE, %eax # mutexes.head, D.2029
movl %eax, 36(%ebx) # D.2029, <variable>.next
/APP
# 75 "mxfull.cpp" 1
lock cmpxchgl %ebx,__ZN13pthread_mutex7mutexesE # this,
# 0 "" 2
/NO_APP
cmpl %eax, 36(%ebx) # prev, <variable>.next
jne L14 #,
but it's a horrible bit of code. Declaring the memory location as input only,
then clobbering all of memory and potentially confusing the optimisers with
type aliasing casts? It makes me very uneasy.
cheers,
DaveK
// g++ -c mxfull.cpp -o mxfull.o --save-temps -O2 -fverbose-asm
typedef long LONG;
typedef void *HANDLE;
typedef void *PVOID;
typedef char *LPCSTR;
typedef class pthread_mutex *pthread_mutex_t;
typedef class pthread_mutexattr *pthread_mutexattr_t;
typedef class pthread *pthread_t;
struct SECURITY_ATTRIBUTES;
typedef struct SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES;
extern struct SECURITY_ATTRIBUTES sec_none_nih;
HANDLE __attribute__((__stdcall__)) CreateSemaphoreA(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCSTR);
class verifyable_object
{
public:
long magic;
verifyable_object (long);
virtual ~verifyable_object ();
};
#if 0
// My version
extern __inline__ long
ilockcmpexch (volatile long *t, long v, long c)
{
register long __res __asm ("%eax") = c;
__asm__ __volatile__ ("\n\
lock cmpxchgl %2,%1\n\
": "+a" (__res), "=m" (*t) : "q" (v), "m" (*t) : "memory", "cc");
return __res;
}
#elif 0
// Original version
extern __inline__ long
ilockcmpexch (volatile long *t, long v, long c)
{
register int __res;
__asm__ __volatile__ ("\n\
lock cmpxchgl %3,(%1)\n\
": "=a" (__res), "=q" (t) : "1" (t), "q" (v), "0" (c): "cc");
return __res;
}
#elif 0
// GlibC/uClibC version
extern __inline__ long
ilockcmpexch (volatile long *t, long v, long c)
{
return ({
__typeof (*t) ret;
__asm __volatile ("lock cmpxchgl %2, %1"
: "=a" (ret), "=m" (*t)
: "r" (v), "m" (*t), "0" (c));
ret;
});
}
#elif 01
// Linux-2.6.8-1 version
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
#define LOCK_PREFIX " lock "
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long newv)
{
unsigned long prev;
__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
: "=a"(prev)
: "q"(newv), "m"(*__xg(ptr)), "0"(old)
: "memory");
return prev;
}
extern __inline__ long
ilockcmpexch (volatile long *t, long v, long c)
{
return __cmpxchg (t, c, v);
}
#endif
class pthread_mutexattr: public verifyable_object
{
public:
int pshared;
int mutextype;
pthread_mutexattr ();
~pthread_mutexattr ();
};
template <class list_node> inline void
List_insert (list_node *&head, list_node *node)
{
if (!node)
return;
do
node->next = head;
while ((PVOID)ilockcmpexch((LONG volatile *)(&head),(LONG)(node),(LONG)(node->next)) != node->next);
}
template <class list_node> class List
{
public:
List() : head(__null)
{
}
~List()
{
}
void insert (list_node *node)
{
List_insert (head, node);
}
list_node *head;
};
class pthread_mutex: public verifyable_object
{
public:
unsigned long lock_counter;
HANDLE win32_obj_id;
unsigned int recursion_counter;
LONG condwaits;
pthread_t owner;
int type;
int pshared;
pthread_mutex (pthread_mutexattr * = __null);
~pthread_mutex ();
class pthread_mutex * next;
private:
static List<pthread_mutex> mutexes;
};
List<pthread_mutex> pthread_mutex::mutexes;
pthread_mutex::pthread_mutex (pthread_mutexattr *attr) :
verifyable_object (0xdf0df045 +1),
lock_counter (0),
win32_obj_id (__null), recursion_counter (0),
condwaits (0), owner (__null),
type (1),
pshared (0)
{
win32_obj_id = ::CreateSemaphoreA (&sec_none_nih, 0, 2147483647L, __null);
if (!win32_obj_id)
{
magic = 0;
return;
}
if (attr)
{
if (attr->pshared == 1)
{
magic = 0;
return;
}
type = attr->mutextype;
}
mutexes.insert (this);
}