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 #ifndef __SVAR_DB_HH_DEFINED__
22 #define __SVAR_DB_HH_DEFINED__
23 
24 #include <stdint.h>
25 #include <unistd.h>
26 
27 #include <iostream>
28 #include <vector>
29 
30 #include "Common.hh"
31 #include "ProcessorID.hh"
32 #include "Svar_record.hh"
33 
34 using namespace std;
35 
36 #if APSERVER_TRANSPORT == 1
37 # define ABSTRACT_OFFSET 1
38 #else
39 # define ABSTRACT_OFFSET 0
40 #endif
41 
42 //-----------------------------------------------------------------------------
43 /// a pointer to one record (one shared variable) of the shared Svar_DB_memory
44 class Svar_record_P
45 {
46 public:
47    /// constructor: fetch record with key \b key from APserver
48    Svar_record_P(SV_key key);
49 
50    /// return pointer to the record (overloaded -> operator)
operator ->() const51    const Svar_record * operator->() const
52       { return &cache; }
53 
54 protected:
55    /// the last fetched record
56    static Svar_record cache;
57 
58 private:
59    /// don't copy...
60   Svar_record_P(const Svar_record_P & other);
61 
62    /// don't copy...
63    Svar_record_P & operator =(const Svar_record_P & other);
64 };
65 //-----------------------------------------------------------------------------
66 # define READ_RECORD(key, open_act, closed_act)		\
67     if (Svar_DB::APserver_available())			\
68          { const Svar_record_P svar(key); open_act }	\
69     else { closed_act }
70 
71 /// Access to the shared variable database in APserver
72 class Svar_DB
73 {
74 public:
75    /// open (and possibly initialize) the shared variable database
76    static void init(const char * bin_path, const char * prog, int retry_max,
77                     bool logit, bool do_svars);
78 
79    /// open (and possibly initialize) the shared variable database
80    void open_shared_memory(const char * progname, bool logit, bool do_svars);
81 
82    /// match a new offer against the DB. Return: 0 on error, 1 if the
83    /// new offer was inserted into the DB (sicne no match was found), or
84    /// 2 if a pending offer was found. In the latter case, the pending offer
85    /// was removed and its relevant data returned through the d_... args.
86    static SV_key match_or_make(const uint32_t * UCS_varname,
87                                const AP_num3 & to, const Svar_partner & from);
88 
89    /// return true if \b id is registered in APserver
90    static bool is_registered_id(const AP_num3 & id);
91 
92    /// get TCP socket to APserver, complain if not connected
93    static TCP_socket get_Svar_DB_tcp(const char * calling_function);
94 
95    /// retract an offer, return previous coupling
96    static void retract_var(SV_key key);
97 
98    /// return pointer to varname or 0 if key does not exist
get_svar_name(SV_key key)99    static const uint32_t * get_svar_name(SV_key key)
100       {
101         READ_RECORD(key, return svar->get_svar_name(); , return 0; )
102       }
103 
104    /// find ID of the procesdsor that has offered the variable with key \b key
105    static AP_num3 find_offering_id(SV_key key);
106 
107    /// add processors with pending offers to \b to_proc. Duplicates
108    /// are OK and will be removed later
109    static void get_offering_processors(AP_num to_proc,
110                                        std::vector<AP_num> & processors);
111 
112    /// return all variables shared between \b to_proc and \b from_proc
113    static void get_offered_variables(AP_num to_proc, AP_num from_proc,
114                                      std::vector<uint32_t> & varnames);
115 
116    /// return coupling of \b entry with \b key.
get_coupling(SV_key key)117    static SV_Coupling get_coupling(SV_key key)
118       {
119         READ_RECORD(key, return svar->get_coupling(); , return NO_COUPLING;)
120       }
121 
122    /// return the current control vector of this variable
get_control(SV_key key)123    static Svar_Control get_control(SV_key key)
124       {
125         READ_RECORD(key, return svar->get_control(); , return NO_SVAR_CONTROL; )
126       }
127 
128    /// set the current control vector of this variable
129    static void set_control(SV_key key, Svar_Control ctl);
130 
131    /// return the current state of this variable
get_state(SV_key key)132    static Svar_state get_state(SV_key key)
133       {
134         READ_RECORD(key, return svar->get_state(); , return SVS_NOT_SHARED; )
135       }
136 
137    /// true if key is shared between workspaces (as opposed to shared between
138    /// a workspace and an AP
is_ws_to_ws(SV_key key)139    static bool is_ws_to_ws(SV_key key)
140       {
141         READ_RECORD(key, return svar->is_ws_to_ws(); , return false; )
142       }
143 
144    /// return true iff setting the shared variable is allowed
145    static bool may_set(SV_key key, int attempt);
146 
147    /// return true iff reading the shared variable is allowed
148    static bool may_use(SV_key key, int attempt);
149 
150    /// set the current state of this variable
151    static void set_state(SV_key key, bool used, const char * loc);
152 
153    /// some shared variables names belong to a pair, like CTL and DAT in AP210.
154    /// return the key of the other variable
155    static SV_key find_pairing_key(SV_key key);
156 
157    /// clear all events, return the current event bitmap.
158    static Svar_event clear_all_events(AP_num3 id);
159 
160    /// return events for processor \b proc
161    static SV_key get_events(Svar_event & events, AP_num3 proc);
162 
163    /// set an event for proc (and maybe also for key)
164    static void add_event(SV_key key, AP_num3 id, Svar_event event);
165 
166    /// print the database
167    static void print(ostream & out);
168 
169    /// return a socket that is connect to APserver
170    static TCP_socket connect_to_APserver(const char * bin_path,
171                                          const char * prog, int retry_max,
172                                          bool logit);
173 
174    /// close TCP connection to APserver
disconnect()175    static void disconnect()
176       {
177         if (DB_tcp != NO_TCP_SOCKET)
178            { ::close(DB_tcp);   DB_tcp = NO_TCP_SOCKET; }
179       }
180 
181    /// return true if the connection to APserver is up
APserver_available()182    static bool APserver_available()
183       { return DB_tcp != NO_TCP_SOCKET; }
184 
185    /// return the fd towards APserver
get_DB_tcp()186    static TCP_socket get_DB_tcp()
187       { return DB_tcp; }
188 
189    /// print TCP error information
190    static void DB_tcp_error(const char * op, int got, int expected);
191 
192 protected:
193    /// start an APserver process, return true on failure
194    static bool start_APserver(const char * server_sockname,
195                               const char * bin_dir, bool logit);
196 
197    /// the TCP connection to APserver, NO_TCP_SOCKET if invalid
198    static TCP_socket DB_tcp;
199 
200    /// The TCP port of APserver
201    static uint16_t APserver_port;
202 
203 private:
204    /// don't create...
205   Svar_DB();
206 
207    /// don't copy...
208   Svar_DB(const Svar_DB & other);
209 
210    /// don't copy...
211    Svar_DB& operator =(const Svar_DB & other);
212 };
213 
214 #endif // __SVAR_DB_HH_DEFINED__
215