xref: /aoo42x/main/sal/osl/unx/interlck.c (revision 1309f2c9)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 
29 #include "system.h"
30 
31 #include <osl/interlck.h>
32 #include <osl/diagnose.h>
33 
34 #if  ( defined ( SOLARIS ) || defined ( NETBSD ) ) && defined ( SPARC )
35 #error please use asm/interlck_sparc.s
36 #elif defined ( SOLARIS) && defined ( X86 )
37 #error please use asm/interlck_x86.s
38 #elif defined ( GCC ) && ( defined ( X86 ) || defined ( X86_64 ) )
39 /* That's possible on x86-64 too since oslInterlockedCount is a sal_Int32 */
40 
41 extern int osl_isSingleCPU;
42 
43 /*****************************************************************************/
44 /* osl_incrementInterlockedCount */
45 /*****************************************************************************/
46 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
47 {
48     register oslInterlockedCount nCount asm("%eax");
49 
50     nCount = 1;
51 
52     if ( osl_isSingleCPU ) {
53         __asm__ __volatile__ (
54             "xaddl %0, %1\n\t"
55         :   "+r" (nCount), "+m" (*pCount)
56         :   /* nothing */
57         :   "memory");
58     }
59     else {
60         __asm__ __volatile__ (
61             "lock\n\t"
62             "xaddl %0, %1\n\t"
63         :   "+r" (nCount), "+m" (*pCount)
64         :   /* nothing */
65         :   "memory");
66     }
67 
68     return ++nCount;
69 }
70 
71 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
72 {
73     register oslInterlockedCount nCount asm("%eax");
74 
75     nCount = -1;
76 
77     if ( osl_isSingleCPU ) {
78         __asm__ __volatile__ (
79             "xaddl %0, %1\n\t"
80         :   "+r" (nCount), "+m" (*pCount)
81         :   /* nothing */
82         :   "memory");
83     }
84     else {
85         __asm__ __volatile__ (
86             "lock\n\t"
87             "xaddl %0, %1\n\t"
88         :   "+r" (nCount), "+m" (*pCount)
89         :   /* nothing */
90         :   "memory");
91     }
92 
93     return --nCount;
94 }
95 
96 #elif defined ( GCC ) && defined ( POWERPC )
97 
98 /*****************************************************************************/
99 /* osl_incrementInterlockedCount */
100 /*****************************************************************************/
101 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
102 {
103     /* "addi" doesn't work with r0 as second parameter */
104     register oslInterlockedCount nCount __asm__ ("r4");
105 
106     __asm__ __volatile__ (
107         "1: lwarx   %0,0,%2\n\t"
108         "   addi    %0,%0,1\n\t"
109         "   stwcx.  %0,0,%2\n\t"
110         "   bne-    1b\n\t"
111         "   isync"
112         : "=&r" (nCount), "=m" (*pCount)
113         : "r" (pCount)
114         : "memory");
115 
116     return nCount;
117 }
118 
119 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
120 {
121     /* "subi" doesn't work with r0 as second parameter */
122     register oslInterlockedCount nCount __asm__ ("r4");
123 
124     __asm__ __volatile__ (
125         "1: lwarx   %0,0,%2\n\t"
126         "   subi    %0,%0,1\n\t"
127         "   stwcx.  %0,0,%2\n\t"
128         "   bne-    1b\n\t"
129         "   isync"
130         : "=&r" (nCount), "=m" (*pCount)
131         : "r" (pCount)
132         : "memory");
133 
134     return nCount;
135 }
136 
137 #elif defined ( GCC ) && defined ( ARM )
138 
139 /*****************************************************************************/
140 /* osl_incrementInterlockedCount */
141 /*****************************************************************************/
142 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
143 {
144 #if defined( ARMV7 ) || defined( ARMV6 )
145     register oslInterlockedCount nCount __asm__ ("r1");
146     int nResult;
147 
148     __asm__ __volatile__ (
149 "1:	ldrex %0, [%3]\n"
150 "	add %0, %0, #1\n"
151 "	strex %1, %0, [%3]\n"
152 "	teq %1, #0\n"
153 "	bne 1b"
154         : "=&r" (nCount), "=&r" (nResult), "=m" (*pCount)
155         : "r" (pCount)
156         : "memory");
157 
158     return nCount;
159 #else
160     return __sync_add_and_fetch( pCount, 1 );
161 #endif
162 }
163 
164 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
165 {
166 #if defined( ARMV7 ) || defined( ARMV6 )
167     register oslInterlockedCount nCount __asm__ ("r1");
168     int nResult;
169 
170     __asm__ __volatile__ (
171 "0:	ldrex %0, [%3]\n"
172 "	sub %0, %0, #1\n"
173 "	strex %1, %0, [%3]\n"
174 "	teq %1, #0\n"
175 "	bne 0b"
176         : "=&r" (nCount), "=&r" (nResult), "=m" (*pCount)
177         : "r" (pCount)
178         : "memory");
179     return nCount;
180 #else
181     return __sync_sub_and_fetch( pCount, 1 );
182 #endif
183 }
184 
185 #else
186 /* use only if nothing else works, expensive due to single mutex for all reference counts */
187 
188 static pthread_mutex_t InterLock = PTHREAD_MUTEX_INITIALIZER;
189 
190 /*****************************************************************************/
191 /* osl_incrementInterlockedCount */
192 /*****************************************************************************/
193 oslInterlockedCount SAL_CALL osl_incrementInterlockedCount(oslInterlockedCount* pCount)
194 {
195     oslInterlockedCount Count;
196 
197     pthread_mutex_lock(&InterLock);
198     Count = ++(*pCount);
199     pthread_mutex_unlock(&InterLock);
200 
201     return (Count);
202 }
203 
204 /*****************************************************************************/
205 /* osl_decrementInterlockedCount */
206 /*****************************************************************************/
207 oslInterlockedCount SAL_CALL osl_decrementInterlockedCount(oslInterlockedCount* pCount)
208 {
209     oslInterlockedCount Count;
210 
211     pthread_mutex_lock(&InterLock);
212     Count = --(*pCount);
213     pthread_mutex_unlock(&InterLock);
214 
215     return (Count);
216 }
217 
218 #endif /* default */
219