-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathclass_extra.c
More file actions
143 lines (124 loc) · 3.51 KB
/
class_extra.c
File metadata and controls
143 lines (124 loc) · 3.51 KB
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
#include "os.h"
#include "kernobjc/types.h"
#include "kernobjc/class.h"
#include "types.h"
#include "class_extra.h"
#include "associative.h"
#define spinlock_do_not_allocate_page 1
#include "spinlock.h"
/*
* It is expected to happen only once per class per class extra (currently
* only used by associated objects) and in current implementation only when
* associating objects directly with a class, which is not often.
*
* Therefore a spinlock is used instead of using a RW lock or mutex, since
* the contention is expected to be minimal if any.
*/
volatile int class_extra_spinlock;
struct objc_class_extra {
struct objc_class_extra *next;
void *data;
unsigned int identifier;
};
/*
* Finds an extra space on the class cl that has 'identifier'.
* Returns NULL if not found.
*/
static inline struct objc_class_extra *
_objc_class_extra_find_no_lock(Class cl, unsigned int identifier)
{
struct objc_class_extra *extra = NULL;
if (cl->extra_space != NULL){
extra = (struct objc_class_extra*)cl->extra_space;
objc_debug_log("Getting extra at address %p\n", extra);
while (extra != NULL) {
if (extra->identifier == identifier){
break;
}
extra = extra->next;
}
}
return extra;
}
/*
* Calls the above method, surrounded by RLOCK.
*/
static inline struct objc_class_extra *
_objc_class_extra_find(Class cl, unsigned int identifier)
{
lock_spinlock(&class_extra_spinlock);
struct objc_class_extra *extra;
extra = _objc_class_extra_find_no_lock(cl, identifier);
unlock_spinlock(&class_extra_spinlock);
return extra;
}
/*
* Locks the WLOCK, and if the extra with the identifier cannot be
* found, creates one and installs it onto class.
*/
static inline struct objc_class_extra *
_objc_class_extra_create(Class cl, unsigned int identifier)
{
objc_debug_log("Creating class extra for class %p[%s]\n", cl,
class_getName(cl));
lock_spinlock(&class_extra_spinlock);
/* See if anyone hasn't added the extra in the meanwhile */
struct objc_class_extra *extra;
extra = _objc_class_extra_find_no_lock(cl, identifier);
if (extra == NULL){
/* Still NULL, need to allocate it */
extra = objc_alloc(sizeof(struct objc_class_extra),
M_CLASS_EXTRA_TYPE);
extra->next = NULL;
extra->identifier = identifier;
extra->data = NULL;
/* Insert it */
if (cl->extra_space == NULL){
cl->extra_space = extra;
}else{
/* Need to insert it to the end of the chain */
struct objc_class_extra *e = cl->extra_space;
while (e->next != NULL){
e = e->next;
}
e->next = extra;
}
}
unlock_spinlock(&class_extra_spinlock);
return extra;
}
/*
* See header for docs.
*/
PRIVATE void **
objc_class_extra_with_identifier(Class cl, unsigned int identifier)
{
struct objc_class_extra *extra = _objc_class_extra_find(cl, identifier);
if (extra == NULL){
extra = _objc_class_extra_create(cl, identifier);
}
return &extra->data;
}
PRIVATE void
objc_class_extra_destroy_for_class(Class cl)
{
/*
* We don't hold any locks since it is assumed that the class is already
* taken out of the class hierarchy.
*/
struct objc_class_extra *extra = NULL;
if (cl->extra_space != NULL){
extra = (struct objc_class_extra*)cl->extra_space;
while (extra != NULL) {
if (extra->identifier == OBJC_ASSOCIATED_OBJECTS_IDENTIFIER){
objc_remove_associated_objects((id)cl);
}else{
objc_abort("Unknown extra identifier %d!\n", extra->identifier);
/** Not reached. */
}
void *old_extra = extra;
extra = extra->next;
objc_dealloc(old_extra, M_CLASS_EXTRA_TYPE);
}
}
}