summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Threading/Interlocked.cs
blob: 7e2c2aeeabfbf8050cb54bb54c4ed213ba4fdeb2 (plain)
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//

using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Versioning;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Security;

namespace System.Threading
{
    // After much discussion, we decided the Interlocked class doesn't need 
    // any HPA's for synchronization or external threading.  They hurt C#'s 
    // codegen for the yield keyword, and arguably they didn't protect much.  
    // Instead, they penalized people (and compilers) for writing threadsafe 
    // code.
    public static class Interlocked
    {
        /******************************
         * Increment
         *   Implemented: int
         *                        long
         *****************************/

        public static int Increment(ref int location)
        {
            return Add(ref location, 1);
        }

        public static long Increment(ref long location)
        {
            return Add(ref location, 1);
        }

        /******************************
         * Decrement
         *   Implemented: int
         *                        long
         *****************************/

        public static int Decrement(ref int location)
        {
            return Add(ref location, -1);
        }

        public static long Decrement(ref long location)
        {
            return Add(ref location, -1);
        }

        /******************************
         * Exchange
         *   Implemented: int
         *                        long
         *                        float
         *                        double
         *                        Object
         *                        IntPtr
         *****************************/

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int Exchange(ref int location1, int value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern long Exchange(ref long location1, long value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern float Exchange(ref float location1, float value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern double Exchange(ref double location1, double value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Object Exchange(ref Object location1, Object value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value);

        public static T Exchange<T>(ref T location1, T value) where T : class
        {
            _Exchange(__makeref(location1), __makeref(value));
            //Since value is a local we use trash its data on return
            //  The Exchange replaces the data with new data
            //  so after the return "value" contains the original location1
            //See ExchangeGeneric for more details           
            return value;
        }

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void _Exchange(TypedReference location1, TypedReference value);

        /******************************
         * CompareExchange
         *    Implemented: int
         *                         long
         *                         float
         *                         double
         *                         Object
         *                         IntPtr
         *****************************/

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern int CompareExchange(ref int location1, int value, int comparand);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern long CompareExchange(ref long location1, long value, long comparand);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern float CompareExchange(ref float location1, float value, float comparand);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern double CompareExchange(ref double location1, double value, double comparand);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern Object CompareExchange(ref Object location1, Object value, Object comparand);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand);

        /*****************************************************************
         * CompareExchange<T>
         * 
         * Notice how CompareExchange<T>() uses the __makeref keyword
         * to create two TypedReferences before calling _CompareExchange().
         * This is horribly slow. Ideally we would like CompareExchange<T>()
         * to simply call CompareExchange(ref Object, Object, Object); 
         * however, this would require casting a "ref T" into a "ref Object", 
         * which is not legal in C#.
         * 
         * Thus we opted to implement this in the JIT so that when it reads
         * the method body for CompareExchange<T>() it gets back the
         * following IL:
         *
         *     ldarg.0 
         *     ldarg.1
         *     ldarg.2
         *     call System.Threading.Interlocked::CompareExchange(ref Object, Object, Object)
         *     ret
         *
         * See getILIntrinsicImplementationForInterlocked() in VM\JitInterface.cpp
         * for details.
         *****************************************************************/

        public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class
        {
            // _CompareExchange() passes back the value read from location1 via local named 'value'
            _CompareExchange(__makeref(location1), __makeref(value), comparand);
            return value;
        }

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void _CompareExchange(TypedReference location1, TypedReference value, Object comparand);

        // BCL-internal overload that returns success via a ref bool param, useful for reliable spin locks.
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern int CompareExchange(ref int location1, int value, int comparand, ref bool succeeded);

        /******************************
         * Add
         *    Implemented: int
         *                         long
         *****************************/

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern int ExchangeAdd(ref int location1, int value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern long ExchangeAdd(ref long location1, long value);

        public static int Add(ref int location1, int value)
        {
            return ExchangeAdd(ref location1, value) + value;
        }

        public static long Add(ref long location1, long value)
        {
            return ExchangeAdd(ref location1, value) + value;
        }

        /******************************
         * Read
         *****************************/
        public static long Read(ref long location)
        {
            return Interlocked.CompareExchange(ref location, 0, 0);
        }

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        public static extern void MemoryBarrier();

        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
        [SuppressUnmanagedCodeSecurity]
        private static extern void _MemoryBarrierProcessWide();

        public static void MemoryBarrierProcessWide()
        {
            _MemoryBarrierProcessWide();
        }
    }
}