summaryrefslogtreecommitdiff
path: root/libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h')
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h115
1 files changed, 115 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h
new file mode 100644
index 000000000..cddd754a8
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <tls.h>
+#include <sysdep.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+#ifdef __ASSEMBLER__
+
+#undef ret
+#define ret
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, nargs) \
+ /* vanilla version */ ` \
+ ENTRY(name##_nocancel) ` \
+ DO_CALL (__NR_##syscall_name) ` \
+ jls [blink] ` \
+ b __syscall_error@plt ` \
+ END(name##_nocancel) ` \
+ /* thread cancellation variant */ ` \
+ ENTRY(name) ` \
+ SINGLE_THREAD_P ` \
+ bz name##_nocancel ` \
+ DOCARGS_##nargs /* stash syscall args */ ` \
+ CENABLE /* call enable_asynccancel */ ` \
+ mov r9, r0 /* Safe-keep mask */ ` \
+ UNDOCARGS_##nargs /* restore syscall args */ ` \
+ DO_CALL (__NR_##syscall_name) ` \
+ push r0 /* save syscall return value */ ` \
+ mov r0, r9 /* prep mask for disable_asynccancel */ ` \
+ CDISABLE ` \
+ pop r0 /* get syscall ret value back */ ` \
+ cmp r0, -1024 ` \
+ jls [blink] ` \
+ b __syscall_error@plt ` \
+ END(name)
+
+#undef PSEUDO_END
+#define PSEUDO_END(name) \
+
+# ifdef IS_IN_libpthread
+# define CENABLE bl __pthread_enable_asynccancel
+# define CDISABLE bl __pthread_disable_asynccancel
+# define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+# define CENABLE bl __libc_enable_asynccancel
+# define CDISABLE bl __libc_disable_asynccancel
+# define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+# define CENABLE bl __librt_enable_asynccancel
+# define CDISABLE bl __librt_disable_asynccancel
+# else
+# error Unsupported library
+# endif
+
+#define DO_CALL(num) \
+ mov r8, num ` \
+ ARC_TRAP_INSN ` \
+ cmp r0, -1024
+
+.macro push reg
+ st.a \reg, [sp, -4]
+.endm
+
+.macro pop reg
+ ld.ab \reg, [sp, 4]
+.endm
+
+#define DOCARGS_0 push blink
+#define UNDOCARGS_0 pop blink
+
+#define DOCARGS_1 DOCARGS_0` push r0
+#define UNDOCARGS_1 pop r0` UNDOCARGS_0
+
+#define DOCARGS_2 DOCARGS_1` push r1
+#define UNDOCARGS_2 pop r1` UNDOCARGS_1
+
+#define DOCARGS_3 DOCARGS_2` push r2
+#define UNDOCARGS_3 pop r2` UNDOCARGS_2
+
+#define DOCARGS_4 DOCARGS_3` push r3
+#define UNDOCARGS_4 pop r3` UNDOCARGS_3
+
+#define DOCARGS_5 DOCARGS_4` push r4
+#define UNDOCARGS_5 pop r4` UNDOCARGS_4
+
+#define DOCARGS_6 DOCARGS_5` push r5
+#define UNDOCARGS_6 pop r5` UNDOCARGS_5
+
+#define DOCARGS_7 DOCARGS_6` push r6
+#define UNDOCARGS_7 pop r6` UNDOCARGS_6
+
+# define SINGLE_THREAD_P \
+ THREAD_SELF r1 ` \
+ ld r2, [r1, MULTIPLE_THREADS_OFFSET]` \
+ cmp r2, 0
+
+/* ld r2, [r1, -TLS_PRE_TCB_SIZE + MULTIPLE_THREADS_OFFSET] */
+#else /* !__ASSEMBLER__ */
+
+/* TBD: Can use @__local_multiple_threads for libc/libpthread like ARM */
+# define SINGLE_THREAD_P \
+ likely(THREAD_GETMEM (THREAD_SELF, header.multiple_threads) == 0)
+
+#endif /* __ASSEMBLER__ */
+
+#endif