/* * 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 #include #ifndef __ASSEMBLER__ # include #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