]>
Commit | Line | Data |
---|---|---|
75f9527c | 1 | /* Copyright (C) 2009-2013 Free Software Foundation, Inc. |
0a35513e AH |
2 | Contributed by Richard Henderson <rth@redhat.com>. |
3 | ||
4 | This file is part of the GNU Transactional Memory Library (libitm). | |
5 | ||
6 | Libitm is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | Libitm is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
13 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | more details. | |
15 | ||
16 | Under Section 7 of GPL version 3, you are granted additional | |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | You should have received a copy of the GNU General Public License and | |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
24 | ||
25 | #include "libitm_i.h" | |
26 | ||
27 | using namespace GTM; | |
28 | ||
29 | struct clone_entry | |
30 | { | |
31 | void *orig, *clone; | |
32 | }; | |
33 | ||
34 | struct clone_table | |
35 | { | |
36 | clone_entry *table; | |
37 | size_t size; | |
38 | clone_table *next; | |
39 | }; | |
40 | ||
41 | static clone_table *all_tables; | |
42 | ||
43 | static void * | |
44 | find_clone (void *ptr) | |
45 | { | |
46 | clone_table *table; | |
47 | ||
48 | for (table = all_tables; table ; table = table->next) | |
49 | { | |
50 | clone_entry *t = table->table; | |
51 | size_t lo = 0, hi = table->size, i; | |
52 | ||
53 | /* Quick test for whether PTR is present in this table. */ | |
54 | if (ptr < t[0].orig || ptr > t[hi - 1].orig) | |
55 | continue; | |
56 | ||
57 | /* Otherwise binary search. */ | |
58 | while (lo < hi) | |
59 | { | |
60 | i = (lo + hi) / 2; | |
61 | if (ptr < t[i].orig) | |
62 | hi = i; | |
63 | else if (ptr > t[i].orig) | |
64 | lo = i + 1; | |
65 | else | |
66 | return t[i].clone; | |
67 | } | |
68 | ||
69 | /* Given the quick test above, if we don't find the entry in | |
70 | this table then it doesn't exist. */ | |
71 | break; | |
72 | } | |
73 | ||
74 | return NULL; | |
75 | } | |
76 | ||
77 | ||
78 | void * ITM_REGPARM | |
79 | _ITM_getTMCloneOrIrrevocable (void *ptr) | |
80 | { | |
81 | void *ret = find_clone (ptr); | |
82 | if (ret) | |
83 | return ret; | |
84 | ||
85 | gtm_thr()->serialirr_mode (); | |
86 | ||
87 | return ptr; | |
88 | } | |
89 | ||
90 | void * ITM_REGPARM | |
91 | _ITM_getTMCloneSafe (void *ptr) | |
92 | { | |
93 | void *ret = find_clone (ptr); | |
94 | if (ret == NULL) | |
95 | abort (); | |
96 | return ret; | |
97 | } | |
98 | ||
99 | static int | |
100 | clone_entry_compare (const void *a, const void *b) | |
101 | { | |
102 | const clone_entry *aa = (const clone_entry *)a; | |
103 | const clone_entry *bb = (const clone_entry *)b; | |
104 | ||
105 | if (aa->orig < bb->orig) | |
106 | return -1; | |
107 | else if (aa->orig > bb->orig) | |
108 | return 1; | |
109 | else | |
110 | return 0; | |
111 | } | |
112 | ||
113 | namespace { | |
114 | ||
115 | // Within find_clone, we know that we are inside a transaction. Because | |
116 | // of that, we have already synchronized with serial_lock. By taking the | |
117 | // serial_lock for write, we exclude all transactions while we make this | |
118 | // change to the clone tables, without having to synchronize on a separate | |
119 | // lock. Do be careful not to attempt a recursive write lock. | |
120 | ||
121 | class ExcludeTransaction | |
122 | { | |
123 | bool do_lock; | |
124 | ||
125 | public: | |
126 | ExcludeTransaction() | |
127 | { | |
128 | gtm_thread *tx = gtm_thr(); | |
129 | do_lock = !(tx && (tx->state & gtm_thread::STATE_SERIAL)); | |
130 | ||
131 | if (do_lock) | |
132 | gtm_thread::serial_lock.write_lock (); | |
133 | } | |
134 | ||
135 | ~ExcludeTransaction() | |
136 | { | |
137 | if (do_lock) | |
138 | gtm_thread::serial_lock.write_unlock (); | |
139 | } | |
140 | }; | |
141 | ||
142 | } // end anon namespace | |
143 | ||
144 | ||
145 | void | |
146 | _ITM_registerTMCloneTable (void *xent, size_t size) | |
147 | { | |
148 | clone_entry *ent = static_cast<clone_entry *>(xent); | |
149 | clone_table *table; | |
150 | ||
151 | table = (clone_table *) xmalloc (sizeof (clone_table)); | |
152 | table->table = ent; | |
153 | table->size = size; | |
154 | ||
155 | qsort (ent, size, sizeof (clone_entry), clone_entry_compare); | |
156 | ||
157 | // Hold the serial_lock while we update the ALL_TABLES datastructure. | |
158 | { | |
159 | ExcludeTransaction exclude; | |
160 | table->next = all_tables; | |
161 | all_tables = table; | |
162 | } | |
163 | } | |
164 | ||
165 | void | |
166 | _ITM_deregisterTMCloneTable (void *xent) | |
167 | { | |
168 | clone_entry *ent = static_cast<clone_entry *>(xent); | |
169 | clone_table *tab; | |
170 | ||
171 | // Hold the serial_lock while we update the ALL_TABLES datastructure. | |
172 | { | |
173 | ExcludeTransaction exclude; | |
174 | clone_table **pprev; | |
175 | ||
176 | for (pprev = &all_tables; | |
177 | tab = *pprev, tab->table != ent; | |
178 | pprev = &tab->next) | |
179 | continue; | |
180 | *pprev = tab->next; | |
181 | } | |
182 | ||
183 | free (tab); | |
184 | } |