about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/microblaze/sysdep-cancel.h
blob: 2fc5c49f2a5f972020e75a9c9511dbc9712d4aca (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* Copyright (C) 2014-2016 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library.  If not, see
   <http://www.gnu.org/licenses/>.  */

#include <sysdep.h>
#include <tls.h>
#ifndef __ASSEMBLER__
# include <nptl/pthreadP.h>
#endif

#if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt)

# if !IS_IN (librt) || !defined(PIC)
#  define AC_STACK_SIZE  16  /* space for r15, async_cancel arg and 2 temp words */
#  define AC_SET_GOT /* empty */
#  define AC_RESTORE_GOT /* empty */
# else
#  define AC_STACK_SIZE  20  /* extra 4 bytes for r20 */
#  define AC_SET_GOT                                                 \
    swi   r20, r1, AC_STACK_SIZE-4;                                  \
    mfs   r20, rpc;                                                  \
    addik r20, r20, _GLOBAL_OFFSET_TABLE_+8;
#  define AC_RESTORE_GOT                                             \
    lwi   r20, r1, AC_STACK_SIZE-4;
# endif

# undef PSEUDO
# define PSEUDO(name, syscall_name, args)                            \
  .text;                                                             \
  ENTRY (name)                                                       \
    SINGLE_THREAD_P(r12);                                            \
    bnei r12, L(pseudo_cancel);                                      \
  .globl __##syscall_name##_nocancel;                                \
  .type __##syscall_name##_nocancel,@function;                       \
__##syscall_name##_nocancel:                                         \
    DO_CALL (syscall_name, args);                                    \
    addik r4, r0, -4095;                                             \
    cmpu  r4, r4, r3;                                                \
    bgei  r4, SYSCALL_ERROR_LABEL;                                   \
    rtsd  r15, 8;                                                    \
    nop;                                                             \
  .size __##syscall_name##_nocancel, .-__##syscall_name##_nocancel;  \
L(pseudo_cancel):                                                    \
    addik r1, r1, -AC_STACK_SIZE;                                    \
    swi   r15, r1, 0;                                                \
    AC_SET_GOT                                                       \
    DOCARGS_##args                                                   \
    CENABLE;                                                         \
    swi   r3, r1, 8;                                                 \
    UNDOCARGS_##args                                                 \
    DO_CALL (syscall_name, args);                                    \
    swi   r3, r1, 12;                                                \
    lwi   r5, r1, 8;                                                 \
    CDISABLE;                                                        \
    lwi   r3, r1, 12;                                                \
    lwi   r15, r1, 0;                                                \
    AC_RESTORE_GOT                                                   \
    addik r1, r1, AC_STACK_SIZE;                                     \
    addik r4, r0, -4095;                                             \
    cmpu  r4, r4, r3;                                                \
    bgei  r4, SYSCALL_ERROR_LABEL;                                   \
    rtsd  r15, 8;                                                    \
    nop;

/*
 * Macros to save/restore syscall arguments across CENABLE
 * The arguments are saved into the caller's stack (original r1 + 4)
 */

# define DOCARGS_0
# define DOCARGS_1  swi   r5, r1, AC_STACK_SIZE + 4;
# define DOCARGS_2  swi   r6, r1, AC_STACK_SIZE + 8; DOCARGS_1
# define DOCARGS_3  swi   r7, r1, AC_STACK_SIZE + 12; DOCARGS_2
# define DOCARGS_4  swi   r8, r1, AC_STACK_SIZE + 16; DOCARGS_3
# define DOCARGS_5  swi   r9, r1, AC_STACK_SIZE + 20; DOCARGS_4
# define DOCARGS_6  swi   r10, r1, AC_STACK_SIZE + 24; DOCARGS_5

# define UNDOCARGS_0
# define UNDOCARGS_1  lwi   r5, r1, AC_STACK_SIZE + 4;
# define UNDOCARGS_2  UNDOCARGS_1 lwi   r6, r1, AC_STACK_SIZE + 8;
# define UNDOCARGS_3  UNDOCARGS_2 lwi   r7, r1, AC_STACK_SIZE + 12;
# define UNDOCARGS_4  UNDOCARGS_3 lwi   r8, r1, AC_STACK_SIZE + 16;
# define UNDOCARGS_5  UNDOCARGS_4 lwi   r9, r1, AC_STACK_SIZE + 20;
# define UNDOCARGS_6  UNDOCARGS_5 lwi   r10, r1, AC_STACK_SIZE + 24;

# ifdef PIC
#  define PSEUDO_JMP(sym)  brlid r15, sym##@PLTPC; addk r0, r0, r0
# else
#  define PSEUDO_JMP(sym)  brlid r15, sym; addk r0, r0, r0
# endif

# if IS_IN (libpthread)
#  define CENABLE PSEUDO_JMP (__pthread_enable_asynccancel)
#  define CDISABLE  PSEUDO_JMP (__pthread_disable_asynccancel)
#  define __local_multiple_threads __pthread_multiple_threads
# elif IS_IN (libc)
#  define CENABLE PSEUDO_JMP (__libc_enable_asynccancel)
#  define CDISABLE  PSEUDO_JMP (__libc_disable_asynccancel)
#  define __local_multiple_threads __libc_multiple_threads
# elif IS_IN (librt)
#  define CENABLE PSEUDO_JMP (__librt_enable_asynccancel)
#  define CDISABLE  PSEUDO_JMP (__librt_disable_asynccancel)
# else
#  error Unsupported library
# endif


# if IS_IN (libpthread) || IS_IN (libc)
#  ifndef __ASSEMBLER__
extern int __local_multiple_threads attribute_hidden;
#   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
#  else
#   if !defined PIC
#    define SINGLE_THREAD_P(reg) lwi reg, r0, __local_multiple_threads;
#   else
#    define SINGLE_THREAD_P(reg)                                     \
      mfs   reg, rpc;                                                \
      addik reg, reg, _GLOBAL_OFFSET_TABLE_+8;                       \
      lwi   reg, reg, __local_multiple_threads@GOT;                  \
      lwi   reg, reg, 0;
#   endif
#  endif
# else
#  ifndef __ASSEMBLER__
#   define SINGLE_THREAD_P                                           \
  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                      \
                                   header.multiple_threads) == 0, 1)
#  else
#   define SINGLE_THREAD_P(reg)                                      \
     lwi reg, r0, MULTIPLE_THREADS_OFFSET(reg)
#  endif
# endif

#elif !defined __ASSEMBLER__

# define SINGLE_THREAD_P (1)
# define NO_CANCELLATION (1)

#endif

#ifndef __ASSEMBLER__
# define RTLD_SINGLE_THREAD_P                                        \
  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                      \
                                   header.multiple_threads) == 0, 1)
#endif