4 * Userspace RCU library - x86 compatibility checks
6 * Copyright (c) 2009 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include <urcu/uatomic_arch.h>
30 * It does not really matter if the constructor is called before using
31 * the library, as long as the caller checks if __urcu_cas_avail < 0 and calls
32 * compat_arch_init() explicitely if needed.
34 int __attribute__((constructor
)) __urcu_cas_init(void);
36 static pthread_mutex_t compat_mutex
= PTHREAD_MUTEX_INITIALIZER
;
43 int __urcu_cas_avail
= -1;
46 * Imported from glibc 2.3.5. linuxthreads/sysdeps/i386/pt-machine.h.
52 __asm__
__volatile__ ("pushfl; popl %0" : "=r" (res
) : );
56 void set_eflags (int newflags
)
58 __asm__
__volatile__ ("pushl %0; popfl" : : "r" (newflags
) : "cc");
61 int compare_and_swap_is_available (void)
63 int oldflags
= get_eflags ();
65 /* Flip AC bit in EFLAGS. */
66 set_eflags (oldflags
^ 0x40000);
67 /* See if bit changed. */
68 changed
= (get_eflags () ^ oldflags
) & 0x40000;
70 set_eflags (oldflags
);
71 /* If the AC flag did not change, it's a 386 and it lacks cmpxchg.
72 Otherwise, it's a 486 or above and it has cmpxchg. */
76 unsigned long _compat_uatomic_cmpxchg(void *addr
, unsigned long old
,
77 unsigned long _new
, int len
)
79 sigset_t newmask
, oldmask
;
83 ret
= sigemptyset(&newmask
);
85 ret
= pthread_sigmask(SIG_SETMASK
, &newmask
, &oldmask
);
87 ret
= pthread_mutex_lock(&compat_mutex
);
93 unsigned char result
= *(unsigned char *)addr
;
95 *(unsigned char *)addr
= (unsigned char)_new
;
100 unsigned short result
= *(unsigned short *)addr
;
102 *(unsigned short *)addr
= (unsigned short)_new
;
107 unsigned int result
= *(unsigned int *)addr
;
109 *(unsigned int *)addr
= (unsigned int)_new
;
113 /* generate an illegal instruction. Cannot catch this with linker tricks
114 * when optimizations are disabled. */
115 __asm__
__volatile__("ud2");
118 ret
= pthread_mutex_unlock(&compat_mutex
);
120 ret
= pthread_sigmask(SIG_SETMASK
, &oldmask
, NULL
);
124 int __urcu_cas_init(void)
126 if (__urcu_cas_avail
< 0)
127 __urcu_cas_avail
= compare_and_swap_is_available();
128 return __urcu_cas_avail
;