1 /*
2 This file is part of GNU APL, a free implementation of the
3 ISO/IEC Standard 13751, "Programming Language APL, Extended"
4
5 Copyright (C) 2008-2015 Dr. Jürgen Sauermann
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program 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
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <errno.h>
22 #include <fcntl.h> /* For O_* constants */
23 #include <signal.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30
31 #include <iomanip>
32
33 #include "Backtrace.hh"
34 #include "Logging.hh"
35 #include "PrintOperator.hh"
36 #include "ProcessorID.hh"
37 #include "Svar_record.hh"
38 #include "Svar_signals.hh"
39
40 extern ostream & get_CERR();
41
42 //=============================================================================
43 const char *
event_name(Svar_event ev)44 event_name(Svar_event ev)
45 {
46 switch(ev)
47 {
48 case SVE_NO_EVENTS: return "(no event)";
49 case SVE_OFFER_MISMATCH: return "offer mismatch";
50 case SVE_OFFER_MATCHED: return "offer matched";
51 case SVE_OFFER_RETRACT: return "offer retracted";
52 case SVE_ACCESS_CONTROL: return "access control changed";
53 case SVE_USE_BY_OFF_SUCCESS: return "use by offering successful";
54 case SVE_USE_BY_OFF_FAILED: return "use by offering failed";
55 case SVE_SET_BY_OFF_SUCCESS: return "set by offering successful";
56 case SVE_SET_BY_OFF_FAILED: return "set by offering failed";
57 case SVE_USE_BY_ACC_SUCCESS: return "use by accepting successful";
58 case SVE_USE_BY_ACC_FAILED: return "use by accepting failed";
59 case SVE_SET_BY_ACC_SUCCESS: return "set by accepting successful";
60 case SVE_SET_BY_ACC_FAILED: return "set by accepting failed";
61 }
62
63 return "(unknown event)";
64 }
65 //-----------------------------------------------------------------------------
66 ostream &
print(ostream & out) const67 Svar_partner::print(ostream & out) const
68 {
69 out << setw(5) << id.proc;
70 if (id.parent) out << "," << left << setw(5) << id.parent << right;
71 else out << " ";
72
73 out << "│" << setw(3) << tcp_fd << "│"
74 << hex << uppercase << setfill('0') << setw(2) << flags
75 << dec << nouppercase << setfill(' ');
76
77 return out;
78 }
79 //-----------------------------------------------------------------------------
80 void
remove_accepting()81 Svar_record::remove_accepting()
82 {
83 accepting.clear();
84 }
85 //-----------------------------------------------------------------------------
86 void
remove_offering()87 Svar_record::remove_offering()
88 {
89 const AP_num3 offered_to = offering.id;
90
91 offering = accepting;
92 accepting.clear();
93 accepting.id = offered_to;
94 }
95 //-----------------------------------------------------------------------------
96 SV_Coupling
retract()97 Svar_record::retract()
98 {
99 const SV_Coupling old_coupling = get_coupling();
100
101 if (ProcessorID::get_id() == offering.id) remove_offering();
102 else if (ProcessorID::get_id() == accepting.id) remove_accepting();
103 else
104 {
105 bad_proc("Svar_record::retract", ProcessorID::get_id());
106 return NO_COUPLING;
107 }
108
109 // clear variable if last partner has retracted, or else send signal
110 // to the remaining partner.
111 //
112 if (get_coupling() == NO_COUPLING) // retract of a non-coupled variable
113 {
114 clear();
115 }
116
117 return old_coupling;
118 }
119 //-----------------------------------------------------------------------------
120 bool
is_ws_to_ws() const121 Svar_record::is_ws_to_ws() const
122 {
123 if (get_coupling() != SV_COUPLED) return offering.id.proc >= AP_FIRST_USER;
124
125 return offering.id.proc >= AP_FIRST_USER &&
126 accepting.id.proc >= AP_FIRST_USER;
127 }
128 //-----------------------------------------------------------------------------
129 bool
match_name(const uint32_t * UCS_other) const130 Svar_record::match_name(const uint32_t * UCS_other) const
131 {
132 // compare INCLUDING terminating 0;
133 for (int v = 0; v < (MAX_SVAR_NAMELEN); ++v)
134 {
135 if (varname[v] != UCS_other[v])
136 {
137 if (varname[v] == 0x22C6) return true; // ⋆
138 if (varname[v] == '*') return true;
139 if (UCS_other[v] == 0x22C6) return true; // ⋆
140 if (UCS_other[v] == '*') return true;
141 return false;
142 }
143 if (varname[v] == 0) return true; // short name
144 }
145
146 return true; // long name
147 }
148 //-----------------------------------------------------------------------------
149 Svar_Control
mirror(int flags)150 mirror(int flags)
151 {
152 int ret = 0;
153 if (flags & SET_BY_OFF) ret |= SET_BY_ACC;
154 if (flags & SET_BY_ACC) ret |= SET_BY_OFF;
155 if (flags & USE_BY_OFF) ret |= USE_BY_ACC;
156 if (flags & USE_BY_ACC) ret |= USE_BY_OFF;
157 return Svar_Control(ret);
158 }
159 //-----------------------------------------------------------------------------
160 Svar_Control
get_control() const161 Svar_record::get_control() const
162 {
163 int ctl = offering.get_control() | accepting.get_control();
164
165 if (ProcessorID::get_id() == accepting.id) ctl = mirror(ctl);
166 return Svar_Control(ctl);
167 }
168 //-----------------------------------------------------------------------------
169 void
set_control(Svar_Control ctl)170 Svar_record::set_control(Svar_Control ctl)
171 {
172 Log(LOG_shared_variables)
173 {
174 get_CERR() << "set_control(" << ctl << ") on ";
175 print_name(get_CERR());
176 get_CERR() << " by " << ProcessorID::get_id().proc << endl;
177 }
178
179 if (ProcessorID::get_id() == offering.id)
180 {
181 offering.set_control(ctl);
182 if (get_coupling() == SV_COUPLED) // fully coupled: inform peer
183 {
184 accepting.events = Svar_event
185 (accepting.events | SVE_ACCESS_CONTROL);
186 }
187 }
188 else if (ProcessorID::get_id() == accepting.id) // hence fully coupled
189 {
190 accepting.set_control(mirror(ctl));
191 offering.events = Svar_event(offering.events | SVE_ACCESS_CONTROL);
192 }
193 else
194 {
195 bad_proc(__FUNCTION__, ProcessorID::get_id());
196 }
197 }
198 //-----------------------------------------------------------------------------
199 Svar_state
get_state() const200 Svar_record::get_state() const
201 {
202 return state;
203 }
204 //-----------------------------------------------------------------------------
205 void
set_state(bool used,const char * loc)206 Svar_record::set_state(bool used, const char * loc)
207 {
208 usleep(50000);
209
210 Log(LOG_shared_variables)
211 {
212 const char * op = used ? "used" : "set";
213 get_CERR() << "set_state(" << op << ") on ";
214 print_name(get_CERR());
215 get_CERR() << " by " << ProcessorID::get_id().proc
216 << " at " << loc << endl;
217 }
218
219 // the control vector as seen by the offering side
220 //
221 const int control = offering.get_control() | accepting.get_control();
222 Svar_event event = SVE_NO_EVENTS;
223 Svar_partner * peer = 0;
224
225 if (ProcessorID::get_id() == offering.id)
226 {
227 peer = &offering;
228 offering.events = SVE_NO_EVENTS; // clear events
229
230 if (used) // offering has used the variable (unless read-back)
231 {
232 if (state == SVS_OFF_HAS_SET) ; // read-back
233 else
234 {
235 if (control & USE_BY_OFF) event = SVE_USE_BY_OFF_SUCCESS;
236 state = SVS_IDLE;
237 }
238 }
239 else // offering has set the variable
240 {
241 if (control & SET_BY_OFF) event = SVE_SET_BY_OFF_SUCCESS;
242 state = SVS_OFF_HAS_SET;
243 }
244 }
245 else if (ProcessorID::get_id() == accepting.id)
246 {
247 peer = &offering;
248 accepting.events = SVE_NO_EVENTS; // clear events
249
250 if (used) // accepting has used the variable (unless read-back)
251 {
252 if (state == SVS_ACC_HAS_SET) ; // read-back
253 else
254 {
255 if (control & USE_BY_ACC) event = SVE_USE_BY_ACC_SUCCESS;
256 state = SVS_IDLE;
257 }
258 }
259 else // accepting has set the variable
260 {
261 if (control & SET_BY_ACC) event = SVE_SET_BY_ACC_SUCCESS;
262 state = SVS_ACC_HAS_SET;
263 }
264 }
265 else // only the partners should call set_state();
266 {
267 bad_proc(__FUNCTION__, ProcessorID::get_id());
268 return;
269 }
270
271 // if access was restricted then inform peer
272 //
273 if (peer && event != SVE_NO_EVENTS)
274 {
275 peer->events = Svar_event(peer->events | event);
276 }
277 }
278 //-----------------------------------------------------------------------------
279 bool
may_use(int attempt)280 Svar_record::may_use(int attempt)
281 {
282 // control restriction as seen by the offering partner
283 //
284 const int control = offering.get_control() | accepting.get_control();
285 const int restriction = control & state;
286
287 if (ProcessorID::get_id() == offering.id)
288 {
289 if ((restriction & USE_BY_OFF) == 0) return true; // no restriction
290
291 if (accepting.is_active() && (attempt == 0))
292 {
293 accepting.events = Svar_event(accepting.events |
294 SVE_USE_BY_OFF_FAILED);
295 }
296 return false;
297 }
298
299 if (ProcessorID::get_id() == accepting.id)
300 {
301 if ((restriction & USE_BY_ACC) == 0) return true; // no restriction
302
303 if (offering.is_active() && (attempt == 0)) // maybe send event to peer
304 {
305 offering.events = Svar_event(offering.events |
306 SVE_USE_BY_ACC_FAILED);
307 }
308 return false;
309 }
310
311 bad_proc(__FUNCTION__, ProcessorID::get_id());
312 return false;
313 }
314 //-----------------------------------------------------------------------------
315 bool
may_set(int attempt)316 Svar_record::may_set(int attempt)
317 {
318 // control restriction as seen by the offering partner
319 //
320 const int control = offering.get_control() | accepting.get_control();
321 const int restriction = control & state;
322
323 if (ProcessorID::get_id() == offering.id)
324 {
325 if ((restriction & SET_BY_OFF) == 0) return true; // no restriction
326
327 if (accepting.is_active() && (attempt == 0)) // maybe send event to peer
328 {
329 accepting.events = Svar_event(accepting.events |
330 SVE_SET_BY_OFF_FAILED);
331 }
332 return false;
333 }
334
335 if (ProcessorID::get_id() == accepting.id)
336 {
337 if ((restriction & SET_BY_ACC) == 0) return true; // no restriction
338
339 if (offering.is_active() && (attempt == 0)) // maybe send event to peer
340 {
341 offering.events = Svar_event(offering.events |
342 SVE_SET_BY_ACC_FAILED);
343 }
344 return false;
345 }
346
347 bad_proc(__FUNCTION__, ProcessorID::get_id());
348 return false;
349 }
350 //-----------------------------------------------------------------------------
351 void
bad_proc(const char * function,const AP_num3 & id) const352 Svar_record::bad_proc(const char * function, const AP_num3 & id) const
353 {
354 get_CERR() << function << "(): proc " << id.proc
355 << " does not match offering proc " << offering.id.proc
356 << " nor accepting proc " << accepting.id.proc << endl;
357 }
358 //-----------------------------------------------------------------------------
359 void
print(ostream & out) const360 Svar_record::print(ostream & out) const
361 {
362 const Svar_state st = get_state();
363 out << "║" << setw(5) << (key & 0xFFFF) << "│" << get_coupling() << "║";
364 offering.print(out) << "║";
365 accepting.print(out) << "║";
366 if (st & SET_BY_OFF) out << "1"; else out << "0";
367 if (st & SET_BY_ACC) out << "1"; else out << "0";
368 if (st & USE_BY_OFF) out << "1"; else out << "0";
369 if (st & USE_BY_ACC) out << "1│"; else out << "0│";
370 print_name(out, varname, 10) << "║" << endl;
371 }
372 //-----------------------------------------------------------------------------
373 ostream &
print_name(ostream & out,const uint32_t * name,int len)374 Svar_record::print_name(ostream & out, const uint32_t * name, int len)
375 {
376 while (*name)
377 {
378 uint32_t uni = *name++;
379 if (uni < 0x80)
380 {
381 out << char(uni);
382 }
383 else if (uni < 0x800)
384 {
385 const uint8_t b1 = uni & 0x3F; uni >>= 6;
386 out << char(uni | 0xC0)
387 << char(b1 | 0x80);
388 }
389 else if (uni < 0x10000)
390 {
391 const uint8_t b2 = uni & 0x3F; uni >>= 6;
392 const uint8_t b1 = uni & 0x3F; uni >>= 6;
393 out << char(uni | 0xE0)
394 << char(b1 | 0x80)
395 << char(b2 | 0x80);
396 }
397 else if (uni < 0x110000)
398 {
399 const uint8_t b3 = uni & 0x3F; uni >>= 6;
400 const uint8_t b2 = uni & 0x3F; uni >>= 6;
401 const uint8_t b1 = uni & 0x3F; uni >>= 6;
402 out << char(uni | 0xE0)
403 << char(b1 | 0x80)
404 << char(b2 | 0x80)
405 << char(b3 | 0x80);
406 }
407
408 --len;
409 }
410
411 while (len-- > 0) out << " ";
412
413 return out;
414 }
415 //-----------------------------------------------------------------------------
416