inserted additional note to look for ChangeLog and AUTHORS file for a log
[platform/upstream/glib.git] / gthread / gthread-nspr.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gthread.c: nspr thread system implementation
5  * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
25  * file for a list of people on the GLib Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 /* 
31  * MT safe
32  */
33
34 #include <prpdce.h>
35 #include <prthread.h>
36 #include <stdlib.h>
37
38 #ifdef G_DISABLE_ASSERT
39
40 #define STDERR_ASSERT(expr)
41
42 #else /* G_DISABLE_ASSERT */
43
44 #define STDERR_ASSERT(expr)                  G_STMT_START{      \
45      if (!(expr))                                               \
46        g_log (G_LOG_DOMAIN,                                     \
47               G_LOG_LEVEL_ERROR,                                \
48               "file %s: line %d: assertion failed: (%s)",       \
49               __FILE__,                                         \
50               __LINE__,                                         \
51               #expr);                   }G_STMT_END
52
53 #endif /* G_DISABLE_ASSERT */
54
55 /* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
56    functions from gmem.c and gmessages.c; */
57
58 static gboolean
59 g_mutex_trylock_nspr_impl (GMutex * mutex)
60 {
61   PRStatus status = PRP_TryLock ((PRLock *) mutex);
62   if (status == PR_SUCCESS)
63     {
64       return TRUE;
65     }
66   return FALSE;
67 }
68
69 static void
70 g_cond_wait_nspr_impl (GCond * cond,
71                        GMutex * entered_mutex)
72 {
73   PRStatus status = PRP_NakedWait ((PRCondVar *) cond, 
74                                    (PRLock *) entered_mutex,
75                                    PR_INTERVAL_NO_TIMEOUT);
76   g_assert (status == PR_SUCCESS);
77 }
78
79 #define G_MICROSEC 1000000
80
81 static gboolean
82 g_cond_timed_wait_nspr_impl (GCond * cond,
83                              GMutex * entered_mutex,
84                              GTimeVal * abs_time)
85 {
86   PRStatus status;
87   PRIntervalTime interval;
88   GTimeVal current_time;
89   glong microsecs;
90
91   g_return_val_if_fail (cond != NULL, FALSE);
92   g_return_val_if_fail (entered_mutex != NULL, FALSE);
93
94   g_get_current_time (&current_time);
95
96   if (abs_time->tv_sec < current_time.tv_sec ||
97       (abs_time->tv_sec == current_time.tv_sec &&
98        abs_time->tv_usec < current_time.tv_usec))
99     return FALSE;
100
101   interval = PR_SecondsToInterval (abs_time->tv_sec - current_time.tv_sec);
102   microsecs = abs_time->tv_usec - current_time.tv_usec;
103   if (microsecs < 0)
104     interval -= PR_MicrosecondsToInterval (-microsecs);
105   else
106     interval += PR_MicrosecondsToInterval (microsecs);
107
108   status = PRP_NakedWait ((PRCondVar *) cond, (PRLock *) entered_mutex,
109                           interval);
110
111   g_assert (status == PR_SUCCESS);
112
113   g_get_current_time (&current_time);
114
115   if (abs_time->tv_sec < current_time.tv_sec ||
116       (abs_time->tv_sec == current_time.tv_sec &&
117        abs_time->tv_usec < current_time.tv_usec))
118     return FALSE;
119   return TRUE;
120 }
121
122 typedef struct _GPrivateNSPRData GPrivateNSPRData;
123 struct _GPrivateNSPRData
124   {
125     gpointer data;
126     GDestroyNotify destructor;
127   };
128
129 typedef struct _GPrivateNSPR GPrivateNSPR;
130 struct _GPrivateNSPR
131   {
132     PRUintn private_key;
133     GDestroyNotify destructor;
134   };
135
136 static GPrivateNSPRData *
137 g_private_nspr_data_constructor (GDestroyNotify destructor, gpointer data)
138 {
139   /* we can not use g_new and friends, as they might use private data by
140      themself */
141   GPrivateNSPRData *private_key = malloc (sizeof (GPrivateNSPRData));
142   g_assert (private_key);
143   private_key->data = data;
144   private_key->destructor = destructor;
145
146   return private_key;
147 }
148
149 static void
150 g_private_nspr_data_destructor (gpointer data)
151 {
152   GPrivateNSPRData *private_key = data;
153   if (private_key->destructor && private_key->data)
154     (*private_key->destructor) (private_key->data);
155   free (private_key);
156 }
157
158 static GPrivate *
159 g_private_new_nspr_impl (GDestroyNotify destructor)
160 {
161   GPrivateNSPR *result = g_new (GPrivateNSPR, 1);
162   PRStatus status = PR_NewThreadPrivateIndex (&result->private_key,
163                                             g_private_nspr_data_destructor);
164   g_assert (status == PR_SUCCESS);
165
166   result->destructor = destructor;
167   return (GPrivate *) result;
168 }
169
170 /* NOTE: the functions g_private_get and g_private_set may not use
171    functions from gmem.c and gmessages.c */
172
173 static GPrivateNSPRData *
174 g_private_nspr_data_get (GPrivateNSPR * private_key)
175 {
176   GPrivateNSPRData *data;
177
178   STDERR_ASSERT (private_key);
179
180   data = PR_GetThreadPrivate (private_key->private_key);
181   if (!data)
182     {
183       data = g_private_nspr_data_constructor (private_key->destructor, NULL);
184       STDERR_ASSERT (PR_SetThreadPrivate (private_key->private_key, data)
185                      == PR_SUCCESS);
186     }
187
188   return data;
189 }
190
191 static void
192 g_private_set_nspr_impl (GPrivate * private_key, gpointer value)
193 {
194   if (!private_key)
195     return;
196
197   g_private_nspr_data_get ((GPrivateNSPR *) private_key)->data = value;
198 }
199
200 static gpointer
201 g_private_get_nspr_impl (GPrivate * private_key)
202 {
203   if (!private_key)
204     return NULL;
205
206   return g_private_nspr_data_get ((GPrivateNSPR *) private_key)->data;
207 }
208
209 static GThreadFunctions g_thread_functions_for_glib_use_default =
210 {
211   (GMutex * (*)())PR_NewLock,
212   (void (*)(GMutex *)) PR_Lock,
213   g_mutex_trylock_nspr_impl,
214   (void (*)(GMutex *)) PR_Unlock,
215   (void (*)(GMutex *)) PR_DestroyLock,
216   (GCond * (*)())PRP_NewNakedCondVar,
217   (void (*)(GCond *)) PRP_NakedNotify,
218   (void (*)(GCond *)) PRP_NakedBroadcast,
219   g_cond_wait_nspr_impl,
220   g_cond_timed_wait_nspr_impl,
221   (void (*)(GCond *)) PRP_DestroyNakedCondVar,
222   g_private_new_nspr_impl,
223   g_private_get_nspr_impl,
224   g_private_set_nspr_impl
225 };