ObjFW  Check-in [f65ad67272]

Overview
Comment:runtime: Rewrite synchronized.m.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f65ad672721eecd043851484347bc691a808661365918e4dc63c8600c2b5af0a
User & Date: js on 2012-08-05 10:45:42
Other Links: manifest | tags
Context
2012-08-05
12:17
Use -Wno-objc-root-class if available. check-in: 0c87d8f53b user: js tags: trunk
10:45
runtime: Rewrite synchronized.m. check-in: f65ad67272 user: js tags: trunk
10:45
Add of_rmutex_t, a reentrant mutex implementation. check-in: 1cb3d9fef9 user: js tags: trunk
Changes

Modified src/runtime/synchronized.m from [9fc3b19498] to [e89280c879].

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
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







-
-
-






-
-
+
+
-
-
-
-
+
+
+


-
-
-
-
-
-
-
-
-
-











-
-
+
-
-


-
+

+
-
-
+
+
-
-
-
-
-
+

-
-
+
-

-
-
+
-
-
-
-
+
-
-

-
-
+
-
-
-
-
+
-
-

-
-
-
-
+
+
+
+
-
-
-
+
+
-
-
+
-
-
-
+
-
-
-
-
-
-
+
-
-
+
-
-
-
-
+
+
+
-

-
-
+
-
-
+
-
-
-
-
-
-
+
+
+
+
-
-
+
-
-







-
-
+
-
-


-
+

-
-
+
+
-
-
-
-
+
-
-
-
+
-
-
+

-
+
-
-
-
-
+
-

-
+
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
+
+
-
-
+
-
-
-
-
-
-
-
+
+
-
-
+

-
-
+
+

-
-
-
+
+
+
-
-
-
+

 * file.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <sys/types.h>

#import "runtime.h"
#import "runtime-private.h"
#import "threading.h"

struct lock_s {
	id	    object;
	size_t	    count;
	id	      object;
	int	      count;
	size_t	    recursion;
	of_thread_t thread;
	of_mutex_t  mutex;
};
	of_rmutex_t   rmutex;
	struct lock_s *next;
} *locks = NULL;

static of_mutex_t mutex;
static struct lock_s *locks = NULL;
static ssize_t numLocks = 0;

#define SYNC_ERR(f)							\
	{								\
		fprintf(stderr, "WARNING: %s failed in line %d!\n"	\
		    "WARNING: This might result in a race "		\
		    "condition!\n", f, __LINE__);			\
		return 1;						\
	}

static void __attribute__((constructor))
init(void)
{
	if (!of_mutex_new(&mutex))
		OBJC_ERROR("Failed to create mutex!")
}

int
objc_sync_enter(id object)
{
	ssize_t i;

	struct lock_s *lock;
	if (object == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");
		OBJC_ERROR("Failed to lock mutex!");

	/* Look if we already have a lock */
	for (i = numLocks - 1; i >= 0; i--) {
		if (locks[i].object == object) {
	for (lock = locks; lock != NULL; lock = lock->next) {
		if (lock->object != object)
			if (of_thread_is_current(locks[i].thread))
				locks[i].recursion++;
			else {
				/* Make sure objc_sync_exit doesn't free it */
				locks[i].count++;
			continue;

				/* Unlock so objc_sync_exit can return */
				if (!of_mutex_unlock(&mutex))
		lock->count++;
					SYNC_ERR("of_mutex_unlock(&mutex)");

				if (!of_mutex_lock(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
		if (!of_mutex_unlock(&mutex))
					SYNC_ERR(
					    "of_mutex_lock(&locks[i].mutex");
				}

			OBJC_ERROR("Failed to unlock mutex!");
				if (!of_mutex_lock(&mutex))
					SYNC_ERR("of_mutex_lock(&mutex)");

				assert(locks[i].recursion == 0);

		if (!of_rmutex_lock(&lock->rmutex))
				/* Update lock's active thread */
				locks[i].thread = of_thread_current();
			}

			OBJC_ERROR("Failed to lock mutex!");
			if (!of_mutex_unlock(&mutex))
				SYNC_ERR("of_mutex_unlock(&mutex)");

			return 0;
		}
	}

		return 0;
	}

	/* Create a new lock */
	if (locks == NULL) {
		if ((locks = malloc(sizeof(struct lock_s))) == NULL) {
			of_mutex_unlock(&mutex);
	if ((lock = malloc(sizeof(*lock))) == NULL)
		OBJC_ERROR("Failed to allocate memory for mutex!");
			SYNC_ERR("malloc(...)");
		}

	} else {
		struct lock_s *new_locks;

	if (!of_rmutex_new(&lock->rmutex))
		if ((new_locks = realloc(locks, (numLocks + 1) *
		    sizeof(struct lock_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("realloc(...)");
		}

		OBJC_ERROR("Failed to create mutex!");
		locks = new_locks;
	}


	locks[numLocks].object = object;
	locks[numLocks].count = 1;
	locks[numLocks].recursion = 0;
	lock->object = object;
	lock->count = 1;
	lock->next = locks;
	locks[numLocks].thread = of_thread_current();

	if (!of_mutex_new(&locks[numLocks].mutex)) {
		of_mutex_unlock(&mutex);
	locks = lock;
		SYNC_ERR("of_mutex_new(&locks[numLocks].mutex");
	}


	if (!of_mutex_lock(&locks[numLocks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_lock(&locks[numLocks].mutex");
	}

	if (!of_mutex_unlock(&mutex))
		OBJC_ERROR("Failed to unlock mutex!");

	if (!of_rmutex_lock(&lock->rmutex))
	numLocks++;

		OBJC_ERROR("Failed to lock mutex!");
	if (!of_mutex_unlock(&mutex))
		SYNC_ERR("of_mutex_unlock(&mutex)");

	return 0;
}

int
objc_sync_exit(id object)
{
	ssize_t i;

	struct lock_s *lock, *last = NULL;
	if (object == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");
		OBJC_ERROR("Failed to lock mutex!");

	for (i = numLocks - 1; i >= 0; i--) {
		if (locks[i].object == object) {
	for (lock = locks; lock != NULL; lock = lock->next) {
		if (lock->object != object) {
			if (locks[i].recursion > 0 &&
			    of_thread_is_current(locks[i].thread)) {
				locks[i].recursion--;

			last = lock;
				if (!of_mutex_unlock(&mutex))
					SYNC_ERR("of_mutex_unlock(&mutex)");

			continue;
				return 0;
			}
		}

			if (!of_mutex_unlock(&locks[i].mutex)) {
		if (!of_rmutex_unlock(&lock->rmutex))
				of_mutex_unlock(&mutex);
				SYNC_ERR("of_mutex_unlock(&locks[i].mutex)");
			}

			OBJC_ERROR("Failed to unlock mutex!");
			locks[i].count--;

			if (locks[i].count == 0) {
		if (--lock->count == 0) {
				struct lock_s *new_locks = NULL;

				if (!of_mutex_free(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
					SYNC_ERR(
					    "of_mutex_free(&locks[i].mutex");
				}

			if (!of_rmutex_free(&lock->rmutex))
				OBJC_ERROR("Failed to destroy mutex!");

			if (last != NULL)
				numLocks--;
				locks[i] = locks[numLocks];

				if (numLocks == 0) {
				last->next = lock->next;
			if (locks == lock)
					free(locks);
					new_locks = NULL;
				locks = lock->next;
				} else if ((new_locks = realloc(locks,
				    numLocks * sizeof(struct lock_s))) ==
				    NULL) {
					of_mutex_unlock(&mutex);
					SYNC_ERR("realloc(...)");
				}


			free(lock);
				locks = new_locks;
			}
		}

			if (!of_mutex_unlock(&mutex))
				SYNC_ERR("of_mutex_unlock(&mutex)");
		if (!of_mutex_unlock(&mutex))
			OBJC_ERROR("Failed to unlock mutex!");

			return 0;
		}
	}
		return 0;
	}


	of_mutex_unlock(&mutex);
	SYNC_ERR("objc_sync_exit()");
	OBJC_ERROR("objc_sync_exit() was called for an object not locked!");
}