/* This file is part of GNU APL, a free implementation of the ISO/IEC Standard 13751, "Programming Language APL, Extended" Copyright (C) 2008-2015 Dr. Jürgen Sauermann This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include /* For O_* constants */ #include #include #include #include #include #include #include #include #include "Backtrace.hh" #include "Logging.hh" #include "PrintOperator.hh" #include "ProcessorID.hh" #include "Svar_record.hh" #include "Svar_signals.hh" extern ostream & get_CERR(); //============================================================================= const char * event_name(Svar_event ev) { switch(ev) { case SVE_NO_EVENTS: return "(no event)"; case SVE_OFFER_MISMATCH: return "offer mismatch"; case SVE_OFFER_MATCHED: return "offer matched"; case SVE_OFFER_RETRACT: return "offer retracted"; case SVE_ACCESS_CONTROL: return "access control changed"; case SVE_USE_BY_OFF_SUCCESS: return "use by offering successful"; case SVE_USE_BY_OFF_FAILED: return "use by offering failed"; case SVE_SET_BY_OFF_SUCCESS: return "set by offering successful"; case SVE_SET_BY_OFF_FAILED: return "set by offering failed"; case SVE_USE_BY_ACC_SUCCESS: return "use by accepting successful"; case SVE_USE_BY_ACC_FAILED: return "use by accepting failed"; case SVE_SET_BY_ACC_SUCCESS: return "set by accepting successful"; case SVE_SET_BY_ACC_FAILED: return "set by accepting failed"; } return "(unknown event)"; } //----------------------------------------------------------------------------- ostream & Svar_partner::print(ostream & out) const { out << setw(5) << id.proc; if (id.parent) out << "," << left << setw(5) << id.parent << right; else out << " "; out << "│" << setw(3) << tcp_fd << "│" << hex << uppercase << setfill('0') << setw(2) << flags << dec << nouppercase << setfill(' '); return out; } //----------------------------------------------------------------------------- void Svar_record::remove_accepting() { accepting.clear(); } //----------------------------------------------------------------------------- void Svar_record::remove_offering() { const AP_num3 offered_to = offering.id; offering = accepting; accepting.clear(); accepting.id = offered_to; } //----------------------------------------------------------------------------- SV_Coupling Svar_record::retract() { const SV_Coupling old_coupling = get_coupling(); if (ProcessorID::get_id() == offering.id) remove_offering(); else if (ProcessorID::get_id() == accepting.id) remove_accepting(); else { bad_proc("Svar_record::retract", ProcessorID::get_id()); return NO_COUPLING; } // clear variable if last partner has retracted, or else send signal // to the remaining partner. // if (get_coupling() == NO_COUPLING) // retract of a non-coupled variable { clear(); } return old_coupling; } //----------------------------------------------------------------------------- bool Svar_record::is_ws_to_ws() const { if (get_coupling() != SV_COUPLED) return offering.id.proc >= AP_FIRST_USER; return offering.id.proc >= AP_FIRST_USER && accepting.id.proc >= AP_FIRST_USER; } //----------------------------------------------------------------------------- bool Svar_record::match_name(const uint32_t * UCS_other) const { // compare INCLUDING terminating 0; for (int v = 0; v < (MAX_SVAR_NAMELEN); ++v) { if (varname[v] != UCS_other[v]) { if (varname[v] == 0x22C6) return true; // ⋆ if (varname[v] == '*') return true; if (UCS_other[v] == 0x22C6) return true; // ⋆ if (UCS_other[v] == '*') return true; return false; } if (varname[v] == 0) return true; // short name } return true; // long name } //----------------------------------------------------------------------------- Svar_Control mirror(int flags) { int ret = 0; if (flags & SET_BY_OFF) ret |= SET_BY_ACC; if (flags & SET_BY_ACC) ret |= SET_BY_OFF; if (flags & USE_BY_OFF) ret |= USE_BY_ACC; if (flags & USE_BY_ACC) ret |= USE_BY_OFF; return Svar_Control(ret); } //----------------------------------------------------------------------------- Svar_Control Svar_record::get_control() const { int ctl = offering.get_control() | accepting.get_control(); if (ProcessorID::get_id() == accepting.id) ctl = mirror(ctl); return Svar_Control(ctl); } //----------------------------------------------------------------------------- void Svar_record::set_control(Svar_Control ctl) { Log(LOG_shared_variables) { get_CERR() << "set_control(" << ctl << ") on "; print_name(get_CERR()); get_CERR() << " by " << ProcessorID::get_id().proc << endl; } if (ProcessorID::get_id() == offering.id) { offering.set_control(ctl); if (get_coupling() == SV_COUPLED) // fully coupled: inform peer { accepting.events = Svar_event (accepting.events | SVE_ACCESS_CONTROL); } } else if (ProcessorID::get_id() == accepting.id) // hence fully coupled { accepting.set_control(mirror(ctl)); offering.events = Svar_event(offering.events | SVE_ACCESS_CONTROL); } else { bad_proc(__FUNCTION__, ProcessorID::get_id()); } } //----------------------------------------------------------------------------- Svar_state Svar_record::get_state() const { return state; } //----------------------------------------------------------------------------- void Svar_record::set_state(bool used, const char * loc) { usleep(50000); Log(LOG_shared_variables) { const char * op = used ? "used" : "set"; get_CERR() << "set_state(" << op << ") on "; print_name(get_CERR()); get_CERR() << " by " << ProcessorID::get_id().proc << " at " << loc << endl; } // the control vector as seen by the offering side // const int control = offering.get_control() | accepting.get_control(); Svar_event event = SVE_NO_EVENTS; Svar_partner * peer = 0; if (ProcessorID::get_id() == offering.id) { peer = &offering; offering.events = SVE_NO_EVENTS; // clear events if (used) // offering has used the variable (unless read-back) { if (state == SVS_OFF_HAS_SET) ; // read-back else { if (control & USE_BY_OFF) event = SVE_USE_BY_OFF_SUCCESS; state = SVS_IDLE; } } else // offering has set the variable { if (control & SET_BY_OFF) event = SVE_SET_BY_OFF_SUCCESS; state = SVS_OFF_HAS_SET; } } else if (ProcessorID::get_id() == accepting.id) { peer = &offering; accepting.events = SVE_NO_EVENTS; // clear events if (used) // accepting has used the variable (unless read-back) { if (state == SVS_ACC_HAS_SET) ; // read-back else { if (control & USE_BY_ACC) event = SVE_USE_BY_ACC_SUCCESS; state = SVS_IDLE; } } else // accepting has set the variable { if (control & SET_BY_ACC) event = SVE_SET_BY_ACC_SUCCESS; state = SVS_ACC_HAS_SET; } } else // only the partners should call set_state(); { bad_proc(__FUNCTION__, ProcessorID::get_id()); return; } // if access was restricted then inform peer // if (peer && event != SVE_NO_EVENTS) { peer->events = Svar_event(peer->events | event); } } //----------------------------------------------------------------------------- bool Svar_record::may_use(int attempt) { // control restriction as seen by the offering partner // const int control = offering.get_control() | accepting.get_control(); const int restriction = control & state; if (ProcessorID::get_id() == offering.id) { if ((restriction & USE_BY_OFF) == 0) return true; // no restriction if (accepting.is_active() && (attempt == 0)) { accepting.events = Svar_event(accepting.events | SVE_USE_BY_OFF_FAILED); } return false; } if (ProcessorID::get_id() == accepting.id) { if ((restriction & USE_BY_ACC) == 0) return true; // no restriction if (offering.is_active() && (attempt == 0)) // maybe send event to peer { offering.events = Svar_event(offering.events | SVE_USE_BY_ACC_FAILED); } return false; } bad_proc(__FUNCTION__, ProcessorID::get_id()); return false; } //----------------------------------------------------------------------------- bool Svar_record::may_set(int attempt) { // control restriction as seen by the offering partner // const int control = offering.get_control() | accepting.get_control(); const int restriction = control & state; if (ProcessorID::get_id() == offering.id) { if ((restriction & SET_BY_OFF) == 0) return true; // no restriction if (accepting.is_active() && (attempt == 0)) // maybe send event to peer { accepting.events = Svar_event(accepting.events | SVE_SET_BY_OFF_FAILED); } return false; } if (ProcessorID::get_id() == accepting.id) { if ((restriction & SET_BY_ACC) == 0) return true; // no restriction if (offering.is_active() && (attempt == 0)) // maybe send event to peer { offering.events = Svar_event(offering.events | SVE_SET_BY_ACC_FAILED); } return false; } bad_proc(__FUNCTION__, ProcessorID::get_id()); return false; } //----------------------------------------------------------------------------- void Svar_record::bad_proc(const char * function, const AP_num3 & id) const { get_CERR() << function << "(): proc " << id.proc << " does not match offering proc " << offering.id.proc << " nor accepting proc " << accepting.id.proc << endl; } //----------------------------------------------------------------------------- void Svar_record::print(ostream & out) const { const Svar_state st = get_state(); out << "║" << setw(5) << (key & 0xFFFF) << "│" << get_coupling() << "║"; offering.print(out) << "║"; accepting.print(out) << "║"; if (st & SET_BY_OFF) out << "1"; else out << "0"; if (st & SET_BY_ACC) out << "1"; else out << "0"; if (st & USE_BY_OFF) out << "1"; else out << "0"; if (st & USE_BY_ACC) out << "1│"; else out << "0│"; print_name(out, varname, 10) << "║" << endl; } //----------------------------------------------------------------------------- ostream & Svar_record::print_name(ostream & out, const uint32_t * name, int len) { while (*name) { uint32_t uni = *name++; if (uni < 0x80) { out << char(uni); } else if (uni < 0x800) { const uint8_t b1 = uni & 0x3F; uni >>= 6; out << char(uni | 0xC0) << char(b1 | 0x80); } else if (uni < 0x10000) { const uint8_t b2 = uni & 0x3F; uni >>= 6; const uint8_t b1 = uni & 0x3F; uni >>= 6; out << char(uni | 0xE0) << char(b1 | 0x80) << char(b2 | 0x80); } else if (uni < 0x110000) { const uint8_t b3 = uni & 0x3F; uni >>= 6; const uint8_t b2 = uni & 0x3F; uni >>= 6; const uint8_t b1 = uni & 0x3F; uni >>= 6; out << char(uni | 0xE0) << char(b1 | 0x80) << char(b2 | 0x80) << char(b3 | 0x80); } --len; } while (len-- > 0) out << " "; return out; } //-----------------------------------------------------------------------------