xref: /trunk/main/sal/osl/unx/interlck.c (revision 4dbb87e9)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 
25 #include "system.h"
26 
27 #include <osl/interlck.h>
28 #include <osl/diagnose.h>
29 
30 #if  ( defined ( SOLARIS ) || defined ( NETBSD ) ) && defined ( SPARC )
31 #error please use asm/interlck_sparc.s
32 #elif defined ( SOLARIS) && defined ( X86 )
33 #error please use asm/interlck_x86.s
34 #elif (defined(__GNUC__) || defined(__clang__)) && (defined(X86) || defined(X86_64))
35 /* That's possible on x86-64 too since oslInterlockedCount is a sal_Int32 */
36 
37 extern int osl_isSingleCPU;
38 
39 /*****************************************************************************/
40 /* osl_incrementInterlockedCount */
41 /*****************************************************************************/
osl_incrementInterlockedCount(oslInterlockedCount * pCount)42 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
43 {
44     register oslInterlockedCount nCount asm("%eax");
45 
46     nCount = 1;
47 
48     if ( osl_isSingleCPU ) {
49         __asm__ __volatile__ (
50             "xaddl %0, %1\n\t"
51         :   "+r" (nCount), "+m" (*pCount)
52         :   /* nothing */
53         :   "memory");
54     }
55     else {
56         __asm__ __volatile__ (
57             "lock\n\t"
58             "xaddl %0, %1\n\t"
59         :   "+r" (nCount), "+m" (*pCount)
60         :   /* nothing */
61         :   "memory");
62     }
63 
64     return ++nCount;
65 }
66 
osl_decrementInterlockedCount(oslInterlockedCount * pCount)67 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
68 {
69     register oslInterlockedCount nCount asm("%eax");
70 
71     nCount = -1;
72 
73     if ( osl_isSingleCPU ) {
74         __asm__ __volatile__ (
75             "xaddl %0, %1\n\t"
76         :   "+r" (nCount), "+m" (*pCount)
77         :   /* nothing */
78         :   "memory");
79     }
80     else {
81         __asm__ __volatile__ (
82             "lock\n\t"
83             "xaddl %0, %1\n\t"
84         :   "+r" (nCount), "+m" (*pCount)
85         :   /* nothing */
86         :   "memory");
87     }
88 
89     return --nCount;
90 }
91 
92 #elif defined ( GCC ) && defined ( POWERPC )
93 
94 /*****************************************************************************/
95 /* osl_incrementInterlockedCount */
96 /*****************************************************************************/
osl_incrementInterlockedCount(oslInterlockedCount * pCount)97 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
98 {
99     /* "addi" doesn't work with r0 as second parameter */
100     register oslInterlockedCount nCount __asm__ ("r4");
101 
102     __asm__ __volatile__ (
103         "1: lwarx   %0,0,%2\n\t"
104         "   addi    %0,%0,1\n\t"
105         "   stwcx.  %0,0,%2\n\t"
106         "   bne-    1b\n\t"
107         "   isync"
108         : "=&r" (nCount), "=m" (*pCount)
109         : "r" (pCount)
110         : "memory");
111 
112     return nCount;
113 }
114 
osl_decrementInterlockedCount(oslInterlockedCount * pCount)115 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
116 {
117     /* "subi" doesn't work with r0 as second parameter */
118     register oslInterlockedCount nCount __asm__ ("r4");
119 
120     __asm__ __volatile__ (
121         "1: lwarx   %0,0,%2\n\t"
122         "   subi    %0,%0,1\n\t"
123         "   stwcx.  %0,0,%2\n\t"
124         "   bne-    1b\n\t"
125         "   isync"
126         : "=&r" (nCount), "=m" (*pCount)
127         : "r" (pCount)
128         : "memory");
129 
130     return nCount;
131 }
132 
133 #elif defined ( GCC ) && defined ( ARM )
134 
135 /*****************************************************************************/
136 /* osl_incrementInterlockedCount */
137 /*****************************************************************************/
osl_incrementInterlockedCount(oslInterlockedCount * pCount)138 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
139 {
140 #if defined( ARMV7 ) || defined( ARMV6 )
141     register oslInterlockedCount nCount __asm__ ("r1");
142     int nResult;
143 
144     __asm__ __volatile__ (
145 "1:	ldrex %0, [%3]\n"
146 "	add %0, %0, #1\n"
147 "	strex %1, %0, [%3]\n"
148 "	teq %1, #0\n"
149 "	bne 1b"
150         : "=&r" (nCount), "=&r" (nResult), "=m" (*pCount)
151         : "r" (pCount)
152         : "memory");
153 
154     return nCount;
155 #else
156     return __sync_add_and_fetch( pCount, 1 );
157 #endif
158 }
159 
osl_decrementInterlockedCount(oslInterlockedCount * pCount)160 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
161 {
162 #if defined( ARMV7 ) || defined( ARMV6 )
163     register oslInterlockedCount nCount __asm__ ("r1");
164     int nResult;
165 
166     __asm__ __volatile__ (
167 "0:	ldrex %0, [%3]\n"
168 "	sub %0, %0, #1\n"
169 "	strex %1, %0, [%3]\n"
170 "	teq %1, #0\n"
171 "	bne 0b"
172         : "=&r" (nCount), "=&r" (nResult), "=m" (*pCount)
173         : "r" (pCount)
174         : "memory");
175     return nCount;
176 #else
177     return __sync_sub_and_fetch( pCount, 1 );
178 #endif
179 }
180 
181 #else
182 /* use only if nothing else works, expensive due to single mutex for all reference counts */
183 
184 static pthread_mutex_t InterLock = PTHREAD_MUTEX_INITIALIZER;
185 
186 /*****************************************************************************/
187 /* osl_incrementInterlockedCount */
188 /*****************************************************************************/
osl_incrementInterlockedCount(oslInterlockedCount * pCount)189 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
190 {
191     oslInterlockedCount Count;
192 
193     pthread_mutex_lock(&InterLock);
194     Count = ++(*pCount);
195     pthread_mutex_unlock(&InterLock);
196 
197     return (Count);
198 }
199 
200 /*****************************************************************************/
201 /* osl_decrementInterlockedCount */
202 /*****************************************************************************/
osl_decrementInterlockedCount(oslInterlockedCount * pCount)203 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
204 {
205     oslInterlockedCount Count;
206 
207     pthread_mutex_lock(&InterLock);
208     Count = --(*pCount);
209     pthread_mutex_unlock(&InterLock);
210 
211     return (Count);
212 }
213 
214 #endif /* default */
215 
216