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