2004-04-22 Dick Porter <dick@ximian.com>
[mono.git] / mono / io-layer / critical-sections.c
1 /*
2  * critical-sections.c:  Critical sections
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13
14 #include "mono/io-layer/wapi.h"
15
16 #include "mono-mutex.h"
17
18 #undef DEBUG
19
20 /* A critical section is really just like a lightweight mutex. It
21  * can't be waited for, and doesn't have a handle.
22  */
23
24 /* According to the MSDN docs, the Microsoft implementation spins a
25  * number of times then waits for a semaphore.  I could implement that
26  * here but I'd need a mutex around the critical section structure
27  * anyway.  So I may as well just use a pthread mutex.
28  */
29 static mono_once_t attr_key_once=MONO_ONCE_INIT;
30 static mono_mutexattr_t attr;
31
32 static void attr_init(void)
33 {
34         int ret;
35         
36         ret = mono_mutexattr_init(&attr);
37         g_assert (ret == 0);
38         
39         ret = mono_mutexattr_settype(&attr, MONO_MUTEX_RECURSIVE);
40         g_assert (ret == 0);
41 }
42
43 /**
44  * InitializeCriticalSection:
45  * @section: The critical section to initialise
46  *
47  * Initialises a critical section.
48  */
49 void InitializeCriticalSection(WapiCriticalSection *section)
50 {
51         int ret;
52         
53         mono_once(&attr_key_once, attr_init);
54         ret = mono_mutex_init(&section->mutex, &attr);
55         g_assert (ret == 0);
56 }
57
58 /**
59  * InitializeCriticalSectionAndSpinCount:
60  * @section: The critical section to initialise.
61  * @spincount: The spin count for this critical section.  Not
62  * currently used.
63  *
64  * Initialises a critical section and sets the spin count.  This
65  * implementation just calls InitializeCriticalSection().
66  *
67  * Return value: %TRUE on success, %FALSE otherwise.  (%FALSE never
68  * happens).
69  */
70 gboolean InitializeCriticalSectionAndSpinCount(WapiCriticalSection *section,
71                                                guint32 spincount G_GNUC_UNUSED)
72 {
73         InitializeCriticalSection(section);
74         
75         return(TRUE);
76 }
77
78 /**
79  * DeleteCriticalSection:
80  * @section: The critical section to delete.
81  *
82  * Releases all resources owned by critical section @section.
83  */
84 void DeleteCriticalSection(WapiCriticalSection *section)
85 {
86         int ret;
87         
88         ret = mono_mutex_destroy(&section->mutex);
89         g_assert (ret == 0);
90 }
91
92 /**
93  * SetCriticalSectionSpinCount:
94  * @section: The critical section to set
95  * @spincount: The new spin count for this critical section.  Not
96  * currently used.
97  *
98  * Sets the spin count for the critical section @section.  The spin
99  * count is currently ignored, and set to zero.
100  *
101  * Return value: The previous spin count.  (Currently always zero).
102  */
103 guint32 SetCriticalSectionSpinCount(WapiCriticalSection *section G_GNUC_UNUSED, guint32 spincount G_GNUC_UNUSED)
104 {
105         return(0);
106 }
107
108 /**
109  * TryEnterCriticalSection:
110  * @section: The critical section to try and enter
111  *
112  * Attempts to enter a critical section without blocking.  If
113  * successful the calling thread takes ownership of the critical
114  * section.
115  *
116  * A thread can recursively call EnterCriticalSection() and
117  * TryEnterCriticalSection(), but must call LeaveCriticalSection() an
118  * equal number of times.
119  *
120  * Return value: %TRUE if the thread successfully locked the critical
121  * section, %FALSE otherwise.
122  */
123 gboolean TryEnterCriticalSection(WapiCriticalSection *section)
124 {
125         int ret;
126         
127         ret=mono_mutex_trylock(&section->mutex);
128         if(ret==0) {
129                 return(TRUE);
130         } else {
131                 return(FALSE);
132         }
133 }
134
135 /**
136  * EnterCriticalSection:
137  * @section: The critical section to enter
138  *
139  * Enters critical section @section, blocking while other threads own
140  * it.  This function doesn't return until the calling thread assumes
141  * ownership of @section.
142  *
143  * A thread can recursively call EnterCriticalSection() and
144  * TryEnterCriticalSection(), but must call LeaveCriticalSection() an
145  * equal number of times.
146  */
147 void EnterCriticalSection(WapiCriticalSection *section)
148 {
149         int stat;
150
151         if ((stat = mono_mutex_lock(&section->mutex)) != 0) {
152                 g_error (G_GNUC_PRETTY_FUNCTION
153                          ": EnterCriticalSection failed: %s", g_strerror(stat));
154         }
155 }
156
157 /**
158  * LeaveCriticalSection:
159  * @section: The critical section to leave
160  *
161  * Leaves critical section @section, relinquishing ownership.
162  *
163  * A thread can recursively call EnterCriticalSection() and
164  * TryEnterCriticalSection(), but must call LeaveCriticalSection() an
165  * equal number of times.
166  */
167 void LeaveCriticalSection(WapiCriticalSection *section)
168 {
169         int ret;
170         
171         ret = mono_mutex_unlock(&section->mutex);
172         g_assert (ret == 0);
173 }
174