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_RECORD_HH_DEFINED__
22 #define __SVAR_RECORD_HH_DEFINED__
23 
24 #include <stdint.h>
25 
26 #include "APL_types.hh"
27 
28 /// The coupling level of a shared variable
29 enum SV_Coupling
30 {
31    NO_COUPLING = 0,   ///< not offered or coupled
32    SV_OFFERED  = 1,   ///< offered but not coupled,
33    SV_COUPLED =  2    ///< coupled
34 };
35 
36 /** shared variables control (what is NOT allowed). Terminology:
37     _OFF: the parner that has first offered the variable,
38     _ACC: the parner that has accepted the  offer
39     _1: the partner reading ot changing the control vector
40     _2: the other partner of _1 (if any)
41 
42    Normally the APL interpreter is _1 == _OFF and the
43    partner is _2 == _ACC. If not (eg. when the partner offers first) then
44    the functions set_control() and get_control() map the _1 and _2 arg (of
45    set_control()) and result (of get_control()) to the proper _OFF and _ACC
46    int in in the flags of the corresponding partner.
47 
48  **/
49 enum Svar_Control
50 {
51                                 //   SET USE
52                                 //   O A O A
53    SET_BY_OFF         = 0x08,   ///< 1 0 0 0: offering proc  can't set (again)
54    SET_BY_ACC         = 0x04,   ///< 0 1 0 0: accepting proc  can't set (again)
55    USE_BY_OFF         = 0x02,   ///< 0 0 1 0: offering proc  can't (yet) use
56    USE_BY_ACC         = 0x01,   ///< 0 0 0 1: accepting proc  can't (yet) use
57    NO_SVAR_CONTROL    = 0,      ///< 0 0 0 0: everything allowed
58    ALL_SVAR_CONTROLS  = SET_BY_OFF | SET_BY_ACC | USE_BY_OFF | USE_BY_ACC,
59    SET_BY_1           = SET_BY_OFF,   ///< if 1 is the offering partner
60    SET_BY_2           = SET_BY_ACC,   ///< if 1 is the offering partner
61    USE_BY_1           = USE_BY_OFF,   ///< if 1 is the offering partner
62    USE_BY_2           = USE_BY_ACC,   ///< if 1 is the offering partner
63 };
64 
65 /// the state of the shared variable
66 enum Svar_state
67 {
68                                                  //    SET USE
69                                                  //    O A O A
70    SVS_NOT_SHARED   = NO_SVAR_CONTROL,           ///<  0 0 0 0
71    SVS_IDLE         = USE_BY_OFF | USE_BY_ACC,   ///<  0 0 1 1
72    SVS_OFF_HAS_SET  = SET_BY_OFF | USE_BY_OFF,   ///<  1 0 1 0
73    SVS_ACC_HAS_SET  = SET_BY_ACC | USE_BY_ACC    ///<  0 1 0 1
74 };
75 
76 /// events for a shared variable
77 enum Svar_event
78 {
79    SVE_NO_EVENTS          = 0,        /// no event pending
80    SVE_OFFER_MISMATCH     = 0x0001,   ///< not matching ⎕SVO
81    SVE_OFFER_MATCHED      = 0x0002,   ///< matching ⎕SVO
82    SVE_OFFER_RETRACT      = 0x0004,   ///< ⎕SVR
83    SVE_ACCESS_CONTROL     = 0x0008,   ///< ⎕SVC by partner
84    SVE_USE_BY_OFF_SUCCESS = 0x0010,   ///< CTL is 1 x x x and offerer USEs var
85    SVE_USE_BY_OFF_FAILED  = 0x0020,   ///< CTL is x 1 x x and offerer USE failed
86    SVE_SET_BY_OFF_SUCCESS = 0x0040,   ///< CTL is x x 1 x and offerer SETs var
87    SVE_SET_BY_OFF_FAILED  = 0x0080,   ///< CTL is x x x 1 and offerer SET failed
88    SVE_USE_BY_ACC_SUCCESS = 0x0100,   ///< CTL is 1 x x x and acceptor USEs var
89    SVE_USE_BY_ACC_FAILED  = 0x0200,   ///< CTL is x 1 x x and acc. USE failed
90    SVE_SET_BY_ACC_SUCCESS = 0x0400,   ///< CTL is x x 1 x and acceptor SETs var
91    SVE_SET_BY_ACC_FAILED  = 0x0800,   ///< CTL is x x x 1 and acc. SET failed
92 };
93 
94 /// return the name for event \b ev
95 extern const char * event_name(Svar_event ev);
96 
97 /// SV_key uniquely identifies a shared variable. It is created when the
98 /// variable is first offered and passed to the share partner when the offer
99 /// is matched. The partner (offering or accepting) is identified by the id
100 /// of the partner.
101 typedef uint64_t SV_key;
102 
103 //-----------------------------------------------------------------------------
104 enum TCP_socket
105 {
106    NO_TCP_SOCKET = -1
107 };
108 //-----------------------------------------------------------------------------
109 /// one of the two partners of a shared vaiable
110 struct Svar_partner
111 {
112    /// constructor: unused share partner
Svar_partnerSvar_partner113    Svar_partner()
114    : id(NO_AP),
115      tcp_fd(NO_TCP_SOCKET),
116      flags(0),
117      events(SVE_NO_EVENTS),
118      active(false)
119    {}
120 
121    /// constructor: specific share partner
Svar_partnerSvar_partner122    Svar_partner(const AP_num3 _id, TCP_socket _tcp_fd)
123    : id(_id),
124      tcp_fd(_tcp_fd),
125      flags(0),
126      events(SVE_NO_EVENTS),
127      active(true)
128    {}
129 
130    /// copy other to \n this
operator =Svar_partner131    void operator =(const Svar_partner & other)
132       {
133         id      = other.id;
134         tcp_fd  = other.tcp_fd;
135         flags   = other.flags;
136         events  = other.events;
137         active  = other.active;
138       }
139 
140    /// clear this partner
clearSvar_partner141    void clear() { new (this) Svar_partner; }
142 
143    /// return true if this partner is active. Note that this can be the case
144    /// even though tcp_fd is invalid.
is_activeSvar_partner145    bool is_active() const
146       { return active; }
147 
148    /// set the control bits of this partner (as seen by the offering partner)
set_controlSvar_partner149    void set_control(Svar_Control ctl)
150       { flags = ctl; }
151 
152    /// return the control bits of this partner (as seen by the offering
153    // partner)
get_controlSvar_partner154    Svar_Control get_control() const
155       { return Svar_Control(flags); }
156 
157    /// print this partner
158    ostream & print(ostream & out) const;
159 
160    /// the processor
161    AP_num3 id;
162 
163    /// the TCP socket of the server towards the partner
164    TCP_socket tcp_fd;
165 
166    /// flags controlled by this partner. The numbers 1 and 2 in the SET_BY_1,
167    /// SET_BY_2 bits refer to this partner as 1 and the other partner as 2.
168    uint16_t flags;
169 
170    /// the events for the partner
171    Svar_event events;
172 
173 protected:
174    /// true if this is a valid (connected) partner
175    bool active;
176 };
177 //-----------------------------------------------------------------------------
178 
179 extern TCP_socket get_TCP_for_key(SV_key key);
180 
181 //-----------------------------------------------------------------------------
182 
183 /// one  shared variable.
184 struct Svar_record
185 {
186    /// a key that uniquely identifies this variable
187    SV_key key;
188 
189    /// true if this is a valid entry.
validSvar_record190    bool valid() const   { return get_coupling() != NO_COUPLING; }
191 
192    /// invalidate this entry
clearSvar_record193    void clear()
194       {
195         key = 0;
196         offering.clear();
197         accepting.clear();
198         state = SVS_NOT_SHARED;
199         varname[0] = 0;
200       }
201 
202    /// remove accepting partner
203    void remove_accepting();
204 
205    /// remove offering partner
206    void remove_offering();
207 
208    /// retract the offer made by the calling ID.
209    SV_Coupling retract();
210 
211    /// return true iff this is a variable shared between APL interpreters
212    /// as opposed to shared with an AP.
213    bool is_ws_to_ws() const;
214 
215    /// complain about \b proc
216    void bad_proc(const char * function, const AP_num3 & ap) const;
217 
218    /// return true if UCS_other matches varname (could be a wildcard match)
219    bool match_name(const uint32_t * UCS_other) const;
220 
221    /// return the coupling of the variable
get_couplingSvar_record222    SV_Coupling get_coupling() const
223        { int ret = 0;   if (offering.is_active())    ++ret;
224                         if (accepting.is_active())   ++ret;
225          return SV_Coupling(ret); }
226 
227 
228    /// return the control bits of this variable
229    Svar_Control get_control() const;
230 
231    /// set the control bits of this variable
232    void set_control(Svar_Control ctl);
233 
234    /// return the state of this variable
235    Svar_state get_state() const;
236 
237    /// return the name of the variable, or 0 if fetching it has failed
get_svar_nameSvar_record238    const uint32_t * get_svar_name() const
239       { return *varname ? varname : 0; }
240 
241    /// update the state when using or setting this variable, and clear events
242    void set_state(bool used, const char * loc);
243 
244    /// return true iff the calling partner may use the current value
245    bool may_use(int attempt);
246 
247    /// return true iff the calling partner may set the current value
248    bool may_set(int attempt);
249 
250    /// print the variable
251    void print(ostream & out) const;
252 
253    /// print a name
254    static ostream & print_name(ostream & out, const uint32_t * name,
255                                int len = MAX_SVAR_NAMELEN);
256 
257    /// print the name of this variable
print_nameSvar_record258    ostream & print_name(ostream & out) const
259       { return print_name(out, varname, 0); }
260 
261    /// name of the offered variable (UCS), 0-terminated
262    uint32_t varname[MAX_SVAR_NAMELEN + 1];
263 
264    /// the partner that has offered the variable first
265    Svar_partner offering;
266 
267    /// the partner that has accepted the offer from \b offering
268    Svar_partner accepting;
269 
270    /// state of this variable
271    Svar_state state;
272 };
273 //-----------------------------------------------------------------------------
274 
275 #if APSERVER_TRANSPORT == 1
276    enum {  ABSTRACT_OFFSET = 1 };
277 #else
278    enum {  ABSTRACT_OFFSET = 0 };
279 #endif
280 
281 #endif // __SVAR_RECORD_HH_DEFINED__
282