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-2013  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 <signal.h>
23 #include <stdio.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/wait.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30 
31 #include <cassert>
32 #include <iomanip>
33 #include <iostream>
34 #include <fstream>
35 #include <vector>
36 
37 #include "APmain.hh"
38 #include "Common.hh"
39 #include "PrintOperator.hh"
40 #include "Svar_DB.hh"
41 #include "Svar_signals.hh"
42 
43 #ifdef DYNAMIC_LOG_WANTED
44 extern bool LOG_startup;
45 extern bool LOG_shared_variables;
46 extern bool LOG_Svar_DB_signals;
47 bool LOG_startup = false;
48 bool LOG_shared_variables = false;
49 bool LOG_Svar_DB_signals = false;
50 #else
51 #endif
52 
53 extern const char * prog_name();
54 
55 //-----------------------------------------------------------------------------
56 
57 bool verbose = false;
58 int event_port = 0;
59 
60 const char * prog = 0;
61 char pref[FILENAME_MAX + 20];
62 
63 /// coupled variables
64 vector<Coupled_var> coupled_vars;
65 
66 /// the place where the AP specific part has detected an error
67 string error_loc = "?";
68 
69 /// the name of this AP (aplXXX where XXX is the processor number)
70 char AP_NAME[40] = "ap" STR(AP_NUM);
71 
72 AP_num3 ProcessorID::id(NO_AP, AP_NULL, AP_NULL);
73 
get_CERR()74 ostream & get_CERR()
75 {
76    return cerr;
77 }
78 //-----------------------------------------------------------------------------
79 uint64_t
now_ms()80 now_ms()
81 {
82 timeval current;
83    gettimeofday(&current, 0);
84 
85 uint64_t ret = current.tv_sec;
86    ret *= 1000;
87    ret += current.tv_usec/1000;
88    return ret;
89 }
90 //-----------------------------------------------------------------------------
91 /// return true if key already exists; otherwise add variable and return false
92 bool
add_var(SV_key key)93 add_var(SV_key key)
94 {
95    for (size_t c = 0; c < coupled_vars.size(); ++c)
96        {
97          Coupled_var & cv = coupled_vars[c];
98          if (key == cv.key)   return true;   // key already exists
99        }
100 
101    // key is new; add it to coupled_vars
102    //
103 Coupled_var cv = { key, 0, 0 };
104    initialize(cv);
105    coupled_vars.push_back(cv);
106 
107    return false;
108 }
109 //-----------------------------------------------------------------------------
110 void
print_vars(ostream & out)111 print_vars(ostream & out)
112 {
113    for (size_t c = 0; c < coupled_vars.size(); ++c)
114        {
115          Coupled_var & cv = coupled_vars[c];
116          get_CERR() << "   key: 0x" << hex << cv.key << dec << " ";
117          const uint32_t * varname = Svar_DB::get_svar_name(cv.key);
118          if (varname)
119             {
120               while (*varname)   get_CERR() << (Unicode)(*varname++);
121             }
122          else
123             {
124               get_CERR() << "(unknown var)";
125             }
126          get_CERR() << endl;
127        }
128 }
129 //-----------------------------------------------------------------------------
130 void
do_Assert(const char * cond,const char * fun,const char * file,int line)131 do_Assert(const char * cond, const char * fun, const char * file, int line)
132 {
133    get_CERR() << "Assertion '" << cond << "' failed at "
134         << file << ":" << line << endl;
135 
136    assert(0);
137 }
138 //-----------------------------------------------------------------------------
139 void
control_C(int)140 control_C(int)
141 {
142 AP_num3 this_proc = ProcessorID::get_id();
143    if (verbose)   get_CERR() << pref << " unregistering processor "
144                        << this_proc << endl;
145 
146    if (verbose)   get_CERR() << pref << " done (got ^C)" << endl;
147 
148    exit(0);
149 }
150 
151 static struct sigaction old_ctl_C_action;
152 static struct sigaction new_ctl_C_action;
153 
154 //-----------------------------------------------------------------------------
usage()155 int usage()
156 {
157    get_CERR()
158 << "Usage:"                            << endl
159 << prog << " [options]"                << endl
160 <<                                        endl
161 << "options:"                          << endl
162 << "    --auto        automatically started (exit after last retract)"  << endl
163 << "    --id num      run as processor num"  << endl
164 << "    --par num     run as child of num"  << endl
165 << "    --gra num     run as grandchild of num"  << endl
166 << "    -h, --help    print this help" << endl
167 << "    -v            verbose"         << endl
168 <<                                        endl;
169 
170    return 1;
171 }
172 //-----------------------------------------------------------------------------
173 TCP_socket tcp2 = NO_TCP_SOCKET;
174 
175 TCP_socket
get_TCP_for_key(SV_key key)176 get_TCP_for_key(SV_key key)
177 {
178    return tcp2;
179 }
180 //-----------------------------------------------------------------------------
181 int
main(int argc,char * argv[])182 main(int argc, char * argv[])
183 {
184 bool need_help = false;
185 bool auto_started = false;
186 
187    prog = argv[0];
188 char bin_path[FILENAME_MAX];
189    strncpy(bin_path, prog, sizeof(bin_path));
190 
191 char * slash = strrchr(bin_path, '/');
192    if (slash)
193       {
194         prog = slash + 1;
195         *slash = 0;
196       }
197 
198    Svar_DB::init(bin_path, prog, /* retry_max */ 10, /* logit */ false,
199                  /* do_svars */  true);
200 
201    if (strrchr(prog, '/'))   prog = strrchr(prog, '/') + 1;
202    snprintf(pref, sizeof(pref) - 1, "%s(%u) ", prog, getpid());
203 
204    // set default processor ID
205    ProcessorID::set_own_ID(AP_num(AP_NUM));
206 
207    for (int a = 1; a < argc; )
208        {
209          const char * opt = argv[a++];
210          const char * val = (a < argc) ? argv[a] : 0;
211 
212          if      (!strcmp(opt, "-h"))             need_help = true;
213          else if (!strcmp(opt, "--help"))         need_help = true;
214          else if (!strcmp(opt, "--auto"))         auto_started = true;
215          else if (!strcmp(opt, "-v"))             verbose = true;
216          else if (!strcmp(opt, "--id") && val)
217                           { ProcessorID::set_own_ID(AP_num(atoi(val))); ++a; }
218          else if (!strcmp(opt, "--par") && val)
219                          { ProcessorID::set_parent_ID(AP_num(atoi(val))); ++a; }
220          else if (!strcmp(opt, "--gra") && val)
221                          { ProcessorID::set_grand_ID(AP_num(atoi(val))); ++a; }
222          else
223             {
224               get_CERR() << pref << ": Bad command line option '"
225                    << argv[a] << "'" << endl;
226               need_help = true;
227             }
228        }
229 
230    if (need_help)   return usage();
231 
232    snprintf(AP_NAME, sizeof(AP_NAME), "apl%u", ProcessorID::get_id().proc);
233 
234    // serious attempt to run: run in the background
235    //
236    if (fork())   return 0;            // parent returns (daemonize)
237 
238    // child code...
239    // register as e.g. AP210-port. We do this BEFORE closing stdout so that
240    // caller of our parent waits until we have closed stdout
241    //
242 
243    memset(&new_ctl_C_action, 0, sizeof(struct sigaction));
244    new_ctl_C_action.sa_handler = &control_C;
245    sigaction(SIGTERM, &new_ctl_C_action, &old_ctl_C_action);
246 
247 Svar_partner this_proc(ProcessorID::get_id(), NO_TCP_SOCKET);
248 
249    // tcp is the "normal" connection to APserver as server
250    // tcp2 is a special connection on which APserver (as client) can
251    // send events to this process.
252    //
253 const TCP_socket tcp = Svar_DB::get_DB_tcp();
254 
255    if (ProcessorID::get_id().proc < AP_FIRST_USER)
256       tcp2 = Svar_DB::connect_to_APserver(0, prog_name(), /* retry_max */ 10,
257                                           verbose);
258 
259    if (tcp == NO_TCP_SOCKET || tcp2 == NO_TCP_SOCKET)
260       {
261         cerr << prog_name() << ":*** connection to APserver failed" << endl;
262         return 3;
263       }
264 
265 string progname(prog_name());
266 
267       { REGISTER_PROCESSOR_c request(tcp, this_proc.id.proc,
268                                           this_proc.id.parent,
269                                           this_proc.id.grand,
270                                           0, progname);
271       }
272 
273    if (this_proc.id.proc < AP_FIRST_USER)
274       { progname += "-EV";
275          REGISTER_PROCESSOR_c request(tcp2, this_proc.id.proc,
276                                             this_proc.id.parent,
277                                             this_proc.id.grand,
278                                             1, progname);
279       }
280 
281    fclose(stdout);   // cause getc() of caller to return EOF !
282 
283    for (bool goon = true; goon;)
284        {
285          uint8_t buff[MAX_SIGNAL_CLASS_SIZE + 40000];
286          char * del = 0;
287          const Signal_base * signal = Signal_base::recv_TCP(tcp2, (char *)buff,
288                                                          sizeof(buff), del, 0);
289 
290          if (signal == 0)   // no signal for 10 seconds
291             {
292               goon = false;
293               if (verbose)   get_CERR() << AP_NAME
294                                         << " done (parent died)" << endl;
295               continue;
296             }
297 
298 #if 0
299 #if AP_NUM == 0
300 cerr << "APnnn got " << signal->get_sigName() << endl;
301 #endif
302 #endif
303          switch(signal->get_sigID())
304             {
305             case sid_MAKE_OFFER:        // a new offer from a peer
306                  if (verbose)   get_CERR() << AP_NAME
307                                            << " got MAKE_OFFER" << endl;
308                  {
309                    const SV_key key = signal->get__MAKE_OFFER__key();
310                    const uint32_t * varname = Svar_DB::get_svar_name(key);
311                   if (varname == 0)
312                      {
313                        get_CERR() << "Could not find svar for key "
314                             << key << " at " << LOC << endl;
315                        break;
316                      }
317 
318                    if (! is_valid_varname(varname))
319                       {
320                        get_CERR() << "Bad varname ";
321                         while (*varname)   get_CERR() << (Unicode)(*varname++);
322                         get_CERR() << " at " << LOC << endl;
323                        break;
324                       }
325 
326                    // make a counter offer (APs 100 and 210) or not (APnnn)
327                    //
328                    if (!make_counter_offer(key))   break;   // APnnn
329 
330                    const AP_num3 offering_id = Svar_DB::find_offering_id(key);
331 
332                    Svar_DB::match_or_make(varname, offering_id, this_proc);
333 
334                    add_var(key);
335 
336                    Svar_DB::set_state(key, true, LOC);
337                  }
338                  break;
339 
340             case sid_RETRACT_OFFER:     // ⎕SVR varname
341                  verbose && get_CERR() << AP_NAME
342                                        << " got RETRACT_OFFER" << endl;
343                  {
344                    const SV_key key = signal->get__RETRACT_OFFER__key();
345                    for (size_t c = 0; c < coupled_vars.size(); ++c)
346                        {
347                          Coupled_var & cv = coupled_vars[c];
348                          if (key == cv.key)
349                             {
350                               retract(cv);
351                               coupled_vars.erase(coupled_vars.begin() + c);
352 
353                               if (coupled_vars.size() == 0 && auto_started)
354                                  {
355                                    if (verbose)      get_CERR() << AP_NAME << " done"
356                                       " (last variable retracted)" << endl;
357                                    goon  = false;
358                                    break;
359                                  }
360                            }
361                        }
362                    Svar_DB::add_event(key, ProcessorID::get_id(),
363                                       SVE_OFFER_RETRACT);
364                  }
365                  break;
366 
367             case sid_GET_VALUE:
368                  if (verbose)   get_CERR() << AP_NAME
369                                            << " got GET_VALUE" << endl;
370                  {
371                    const SV_key key = signal->get__GET_VALUE__key();
372                    APL_error_code error = E_VALUE_ERROR;
373                    bool found = false;
374                    string data;
375                    for (size_t c = 0; c < coupled_vars.size(); ++c)
376                        {
377                          Coupled_var & cv = coupled_vars[c];
378                          if (key == cv.key)
379                             {
380                               found = true;
381                               error_loc = LOC;   error = get_value(cv, data);
382                               break;
383                            }
384                        }
385 
386                    if (!found)
387                       {
388                         get_CERR() << "Key 0x" << hex << key << dec
389                              << " not found. Variables are:"
390                              << endl;
391                         print_vars(get_CERR());
392                         error_loc = LOC;   error = E_VALUE_ERROR;
393                       }
394 
395                    VALUE_IS_c response(tcp2, key, error, error_loc, data);
396                  }
397                  break;
398 
399             case sid_ASSIGN_VALUE:
400                  verbose && get_CERR() << AP_NAME
401                                        << " got ASSIGN_VALUE" << endl;
402                  {
403                    const SV_key key = signal->get__ASSIGN_VALUE__key();
404                    APL_error_code error = E_VALUE_ERROR;
405                    bool found = false;
406                    for (size_t c = 0; c < coupled_vars.size(); ++c)
407                        {
408                          Coupled_var & cv = coupled_vars[c];
409                          if (key == cv.key)
410                             {
411                               found = true;
412                               error_loc = LOC;   error = assign_value(cv,
413                                          signal->get__ASSIGN_VALUE__cdr_value());
414                               break;
415                            }
416                        }
417 
418                    if (!found)
419                       {
420                         get_CERR() << "Key 0x" << hex << key << dec
421                              << " not found. Variables are:"
422                              << endl;
423                         print_vars(get_CERR());
424                         error_loc = LOC;   error = E_VALUE_ERROR;
425                       }
426 
427                    SVAR_ASSIGNED_c response(tcp, key, error, error_loc);
428                  }
429                  break;
430 
431             default: get_CERR() << pref << ": bad signal ID "
432                           << signal->get_sigID() << " ("
433                           << signal->get_sigName() << ")" << endl;
434           }
435 
436          if (del)   delete del;
437        }
438 
439    return 0;
440 }
441 //-----------------------------------------------------------------------------
operator <<(ostream & out,const AP_num3 & ap3)442 ostream & operator << (ostream & out, const AP_num3 & ap3)
443 {
444    return out << ap3.proc << "." << ap3.parent << "." << ap3.grand;
445 }
446 //-----------------------------------------------------------------------------
447 ostream &
operator <<(ostream & os,Unicode uni)448 operator << (ostream & os, Unicode uni)
449 {
450    if (uni < 0x80)      return os << (char)uni;
451 
452    if (uni < 0x800)     return os << (char)(0xC0 | (uni >> 6))
453                                   << (char)(0x80 | (uni & 0x3F));
454 
455    if (uni < 0x10000)    return os << (char)(0xE0 | (uni >> 12))
456                                    << (char)(0x80 | (uni >>  6 & 0x3F))
457                                    << (char)(0x80 | (uni       & 0x3F));
458 
459    if (uni < 0x200000)   return os << (char)(0xF0 | (uni >> 18))
460                                    << (char)(0x80 | (uni >> 12 & 0x3F))
461                                    << (char)(0x80 | (uni >>  6 & 0x3F))
462                                    << (char)(0x80 | (uni       & 0x3F));
463 
464    if (uni < 0x4000000)  return os << (char)(0xF8 | (uni >> 24))
465                                    << (char)(0x80 | (uni >> 18 & 0x3F))
466                                    << (char)(0x80 | (uni >> 12 & 0x3F))
467                                    << (char)(0x80 | (uni >>  6 & 0x3F))
468                                    << (char)(0x80 | (uni       & 0x3F));
469 
470    return os << (char)(0xFC | (uni >> 30))
471              << (char)(0x80 | (uni >> 24 & 0x3F))
472              << (char)(0x80 | (uni >> 18 & 0x3F))
473              << (char)(0x80 | (uni >> 12 & 0x3F))
474              << (char)(0x80 | (uni >>  6 & 0x3F))
475              << (char)(0x80 | (uni       & 0x3F));
476 }
477 //-----------------------------------------------------------------------------
478 
479