From b5a6396a18c84ec04c2706237a8363c2a9c7219e Mon Sep 17 00:00:00 2001 From: steffen Date: Tue, 19 Jan 2021 23:32:20 +0000 Subject: [PATCH] threading changed. --- ChangeLog | 6 ++--- server/locomotive.cc | 58 +++++++++++++++++++++++++++++++++++----- server/locomotive.h | 22 ++++++++++++++++ server/network.cc | 41 +++++++++++------------------ server/network.h | 18 ++++++++++--- server/railway.cc | 61 ++++++++++++++++++++++++++++++++++++++++--- server/railway.h | 8 +++++- server/session.cc | 55 +++++++++++++++++++++----------------- webinterface/track.js | 4 +++ 9 files changed, 205 insertions(+), 68 deletions(-) diff --git a/ChangeLog b/ChangeLog index b9ebf11..b61cac1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,9 @@ +2021-01-19: +- threading should be now more stable no deadlocks + 2021-01-15: - web interface for block assignemt seems ready - saving and loading data from a block. -:q -:q -:q! 2020-12-05: - locomotive fixed division by zero diff --git a/server/locomotive.cc b/server/locomotive.cc index 69ef8e2..24ae27e 100644 --- a/server/locomotive.cc +++ b/server/locomotive.cc @@ -158,12 +158,15 @@ int Locomotives::Change(Locomotive *loco) { if (locomotives[i].name[0] != 0) { // found element if (strncmp(locomotives[i].name, loco->name, REFERENCENAME_LEN) == 0) { + // copy block data + ifree = i; break; } } else if (ifree == -1) ifree = i; } + // element not found add new element if (ifree != -1 && ifree < max) { locomotives[ifree] = *loco; @@ -279,7 +282,8 @@ int Locomotives::SetDestination (string name, string block, int direction) { int Locomotives::SetAssign (string name, string block, int direction) { - int i; + int i, x = -1; + int y = -1; Lock(); for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) @@ -291,13 +295,19 @@ int Locomotives::SetAssign (string name, string block, int direction) { } UnLock(); + while (server->railways.FindReference(&x, &y, block)) { + printf ("%s:%d Reference found at %d, %d\n", __FILE__, __LINE__, x, y); + } + printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__); return 1; } int Locomotives::Reset(string name) { + Railway rw; int i; + JSONParse jp; Lock(); for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) @@ -309,37 +319,73 @@ int Locomotives::Reset(string name) { locomotives[i].blocknext[0] = 0; break; } + + server->railways.ClearLockedby(name); UnLock(); - printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__); return 1; }; int Locomotives::SetMan(string name) { int i; - printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__); + Lock(); + for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) + if (name.compare(locomotives[i].name) == 0) { + debug (0, "Locomotives::SetMan (Name:%s)\n", name.c_str()); + locomotives[i].flags &= ~(LOCO_F_AUTO | LOCO_F_AUTOSTOP | LOCO_F_RANDOM); + break; + } + UnLock(); + SetSpeed(name, 0); + return 1; }; int Locomotives::SetAutoMan(string name) { int i; - printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__); + Lock(); + for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) + if (name.compare(locomotives[i].name) == 0 && (locomotives[i].flags & LOCO_F_AUTO)) { + debug (0, "Locomotives::SetAutoMan (Name:%s)\n", name.c_str()); + locomotives[i].flags |= LOCO_F_AUTOSTOP; + locomotives[i].flags &= ~LOCO_F_RANDOM; + break; + } + UnLock(); + return 1; }; int Locomotives::SetAuto(string name) { int i; - printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__); + Lock(); + for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) + if (name.compare(locomotives[i].name) == 0) { + debug (0, "Locomotives::SetAuto (Name:%s)\n", name.c_str()); + locomotives[i].flags |= LOCO_F_AUTO; + break; + } + UnLock(); + return 1; }; int Locomotives::SetAutoRand(string name) { int i; - printf ("%s:%d %s ************** finish me **************\n", __FILE__, __LINE__, __FUNCTION__); + Lock(); + for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) + if (name.compare(locomotives[i].name) == 0 && (locomotives[i].flags & LOCO_F_AUTO)) { + debug (0, "Locomotives::SetRandom (Name:%s)\n", name.c_str()); + locomotives[i].flags |= LOCO_F_RANDOM; + locomotives[i].flags &= ~LOCO_F_AUTOSTOP; + break; + } + UnLock(); + return 1; }; diff --git a/server/locomotive.h b/server/locomotive.h index cfe1f13..b2bf8b8 100644 --- a/server/locomotive.h +++ b/server/locomotive.h @@ -20,6 +20,26 @@ enum { LOCO_INT_DCC128 }; +enum { + LOCO_OR_NOTHING = 0, + LOCO_OR_SEARCH, // search way (to next block and lock way) + LOCO_OR_PREPARE, // switch turnouts right way (one every 100ms) + // if no turnout has to be set, continue + LOCO_OR_ONTHEWAY, // locomotive is on the way // maybe prepare next block? + // ASSIGN -> PREV, NEXT -> ASSIGN, NEXT <- (empty) + // propabely searching next block (if DEST is set)? + LOCO_OR_ONTHEWAYPREPARE, // prepare way as long as on the way + LOCO_OR_ENTERBLOCK, // got new block ready? + // if NEXT is empty and way not AutoPrepareWay not finished... slow down + LOCO_OR_STOP, // stopping + LOCO_OR_WAIT // wait some time +}; + +struct s_LocoAuto { + int onroute; // LOCO_OR_..... + struct timeval waituntil; // wait until this time for next action (tournout, waiting station...) +}; + struct s_Locomotive { char name[REFERENCENAME_LEN]; // name char ifname[REFERENCENAME_LEN]; // ref. of interface @@ -39,6 +59,8 @@ struct s_Locomotive { char blocknext[REFERENCENAME_LEN]; // next block to go to char blockprev[REFERENCENAME_LEN]; // prev block (mostly assigned block char blockdest[REFERENCENAME_LEN]; // destination block + + int auto_onroute; // LOCO_OR_.... } typedef Locomotive; class Locomotives { diff --git a/server/network.cc b/server/network.cc index 46da3a6..c07f6db 100644 --- a/server/network.cc +++ b/server/network.cc @@ -31,34 +31,27 @@ Network::Network() { thread_running = 0; mtx = { 0 }; mtx = PTHREAD_MUTEX_INITIALIZER; + + mtxsessions = { 0 }; + mtxsessions = PTHREAD_MUTEX_INITIALIZER; } Network::~Network() { list::iterator iter; + LockSessions(); while ((iter = sessions.begin()) != sessions.end()) { Session *s = *iter; sessions.remove(*iter); delete s; } + UnLockSessions(); + Stop(); }; -int Network::LockThread() { - if (pthread_mutex_lock(&mtx) == 0) return 1; - else return 0; -} - - -int Network::UnLockThread() { - if (pthread_mutex_unlock(&mtx) == 0) return 1; - else return 0; -} - - - void Network::ThreadProcess() { list::iterator iteru; Session *s; @@ -146,21 +139,17 @@ void Network::Stop() { } -void Network::_ChangeListPushToAll(string changes) { +void Network::ChangeListPushToAll(string changes) { list::iterator iter; + LockSessions(); for (iter = sessions.begin(); iter != sessions.end(); iter++) { if ((*iter)->GetSessionID() > 0) (*iter)->ChangeListPush(changes); } + UnLockSessions(); }; -void Network::ChangeListPushToAll(string changes) { - LockThread(); - _ChangeListPushToAll(changes); - UnLockThread(); -}; - int Network::ServerLoop() { UNIX *u = NULL; @@ -178,12 +167,14 @@ Session *Network::GetSession(int sid) { Session *s = NULL; list::iterator iter; + LockSessions(); for (iter = sessions.begin(); iter != sessions.end(); iter++) { if ((*iter)->GetSessionID() == sid) { s = *iter; break; } } + UnLockSessions(); return s; }; @@ -247,12 +238,12 @@ int Network::ClientLoop(UNIX *client) { debug (0, "* sid not set, gettin new SID"); session = new Session(rid); sid = session->GetSessionID(); - LockThread(); + LockSessions(); sessions.push_back(session); - UnLockThread(); + UnLockSessions(); } else { - LockThread(); + LockSessions(); // // search for session session = NULL; @@ -262,16 +253,14 @@ int Network::ClientLoop(UNIX *client) { break; } } - UnLockThread(); + UnLockSessions(); } if (session) { JSONElement je; int retval; - LockThread(); retval = session->ProcessData(&json, &jsonout); - UnLockThread(); len = BUFFERSIZE; if (retval) { diff --git a/server/network.h b/server/network.h index 5ff6c3c..ebc4ad5 100644 --- a/server/network.h +++ b/server/network.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,7 @@ using namespace std; #include "modelbahn.h" #include "json.h" - +#include "debug.h" extern int next_sessionID; @@ -38,6 +39,12 @@ private: int sessionID; int randomID; list changes; + pthread_mutex_t mtxchanges; +// void LockChanges() { debug (0," ****** %s ", __FUNCTION__); pthread_mutex_lock(&mtxchanges); }; +// void UnLockChanges() { pthread_mutex_unlock(&mtxchanges); debug (0," ****** %s ", __FUNCTION__); }; + void LockChanges() { pthread_mutex_lock(&mtxchanges); }; + void UnLockChanges() { pthread_mutex_unlock(&mtxchanges); }; + void AddJSONRailway(JSONParse *jp); void DelJSONRailway(JSONParse *jp); @@ -91,6 +98,8 @@ class Network { private: void ThreadProcess(); pthread_mutex_t mtx; + pthread_mutex_t mtxsessions; + pthread_t thread; int thread_running; @@ -102,14 +111,15 @@ private: int ClientLoop(UNIX *u); UNIX sockserver; - void _ChangeListPushToAll (string changes); // not thread save friend class Session; public: Network(); ~Network(); - int LockThread(); - int UnLockThread(); + void Lock() { pthread_mutex_lock(&mtx); }; + void UnLock() { pthread_mutex_unlock(&mtx); }; + void LockSessions() { pthread_mutex_lock(&mtxsessions); }; + void UnLockSessions() { pthread_mutex_unlock(&mtxsessions); }; int Start(); void Stop(); diff --git a/server/railway.cc b/server/railway.cc index 8764a8a..7bef599 100644 --- a/server/railway.cc +++ b/server/railway.cc @@ -96,7 +96,7 @@ JSONParse Railways::GetJSONRailway(int x, int y) { Railway Railways::GetRailwayFromJSON(JSONParse *j) { - string name; + string text; Railway r = { type: RAILWAY_NOTHING, x: 0, @@ -104,9 +104,11 @@ Railway Railways::GetRailwayFromJSON(JSONParse *j) { dir: 0, altdir: 0, maxspeed: -1, - flags: 0 + flags: 0, + name: { 0 } }; r.name[0] = 0; + r.lockedby[0] = 0; j->GetValueInt("x", &r.x); j->GetValueInt("y", &r.y); @@ -115,8 +117,10 @@ Railway Railways::GetRailwayFromJSON(JSONParse *j) { j->GetValueInt("type", &r.type); j->GetValueInt("maxspeed", &r.maxspeed); j->GetValueInt("flags", &r.flags); - j->GetValue("name", &name); - strncpy (r.name, name.c_str(), REFERENCENAME_LEN); + j->GetValue("name", &text); + strncpy (r.name, text.c_str(), REFERENCENAME_LEN); + j->GetValue("lockedby", &text); + strncpy (r.lockedby, text.c_str(), REFERENCENAME_LEN); return r; }; @@ -295,5 +299,54 @@ Railway Railways::Get(int x, int y) { return r; }; +void Railways::ClearLockedby(string name) { + int x, y; + JSONParse jp; + + Lock(); + + for (x = 0; x < width; x++) + for (y = 0; y < height; y++) { + if (name.compare(railways[GetRIdx(x,y)].lockedby) == 0) { + railways[GetRIdx(x,y)].lockedby [0] = 0; + changed = 1; + jp.AddObject("railway",_GetJSONRailway(x,y)); + if(network) network->ChangeListPushToAll(jp.ToString()); + } + } + + UnLock(); +} + + +int Railways::FindReference(int *x, int *y, string name) { + int found = 0; + if (x == NULL || y == NULL) return 0; + if (*x < 0 || *y < 0) { + *x = 0; + *y = 0; + } + Lock(); + for (; found == 0 && *y < height; (*y)++) { + if (*x >= width) *x = 0; + else (*x)++; + + for (; found == 0 && *x < width; (*x)++) { + if (strncmp (railways[GetRIdx(*x, *y)].name, name.c_str(), REFERENCENAME_LEN) == 0) { + found = 1; + break; + } + } + } + UnLock(); + + if (*x < width && *y < height) return 1; + else return 0; +}; + + +int FindWay(string blockstart, string blockend, string lockedfor, string *next) { + return 0; +}; diff --git a/server/railway.h b/server/railway.h index 035e308..328ee77 100644 --- a/server/railway.h +++ b/server/railway.h @@ -64,6 +64,7 @@ class Railways { int changed; pthread_mutex_t mtx; + int Lock(); int UnLock(); int GetRIdx(int x, int y); @@ -86,11 +87,16 @@ class Railways { void ClearChanged() { changed = 0; }; int Change(Railway *rw); - Railway RailwayGet(int x, int y) {return railways[GetRIdx(x, y)];}; + void ClearLockedby(string name); + + Railway RailwayGet(int x, int y) {return railways[GetRIdx(x, y)];}; // no lock JSONParse GetJSONRailway(int x, int y); JSONParse GetJSONTrack(); void GetJSONAll(JSONParse *json); Railway GetRailwayFromJSON(JSONParse *j); + + int FindReference(int *x, int *y, string name); + int FindWay(string blockstart, string blockend, string lockedfor, string *next); }; #endif diff --git a/server/session.cc b/server/session.cc index 327386b..0ad2c4a 100644 --- a/server/session.cc +++ b/server/session.cc @@ -9,7 +9,11 @@ int Session::SendData(UNIX *u, string data) { return 0; }; + Session::Session(int rid) { + mtxchanges = { 0 }; + mtxchanges = PTHREAD_MUTEX_INITIALIZER; + sessionID = random(); randomID = rid; changes.clear(); @@ -186,7 +190,9 @@ int Session::ProcessData(JSONParse *jin, JSONParse *jout) { // add chenges which need to be send to the clients // void Session::ChangeListPush(string chng) { + LockChanges(); changes.push_back(chng); + UnLockChanges(); }; @@ -203,13 +209,14 @@ JSONElement Session::ChangeListGet() { je.name = "changes"; je.value = "["; + LockChanges(); for (iter = changes.begin(); iter != changes.end(); iter++) { if (iter != changes.begin()) je.value += ",\n "; else je.value += "\n "; je.value += (*iter); } - changes.clear(); + UnLockChanges(); je.value += "]"; @@ -241,7 +248,7 @@ void Session::AddJSONRailway(JSONParse *jp) { server->RailwayChange(&r); jout.Clear(); jout.AddObject("railway", server->RailwayGetJSONRailway(r.x, r.y)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); } @@ -268,7 +275,7 @@ void Session::DelJSONRailway(JSONParse *jp) { server->RailwayChange(&r); jout.Clear(); jout.AddObject("railway", server->RailwayGetJSONRailway(r.x, r.y)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); } @@ -292,7 +299,7 @@ void Session::AddJSONInterface(JSONParse *jp) { server->InterfaceChange(&iface); jout.Clear(); jout.AddObject("interface", server->InterfaceGetJSON(iface.name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -318,7 +325,7 @@ void Session::DelJSONInterface(JSONParse *jp) { jout.Clear(); s = iface.name; jout.AddObject("interfacedelete", s); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -342,7 +349,7 @@ void Session::AddJSONSensor(JSONParse *jp) { server->SensorChange(&se); jout.Clear(); jout.AddObject("sensor", server->SensorGetJSON(se.name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -368,7 +375,7 @@ void Session::DelJSONSensor(JSONParse *jp) { jout.Clear(); s = se.name; jout.AddObject("sensordelete", s); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -392,7 +399,7 @@ void Session::AddJSONLocomotive(JSONParse *jp) { server->LocomotiveChange(&loco); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco.name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -434,7 +441,7 @@ void Session::SetJSONLocomotive(JSONParse *jp) { } jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loconame)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -459,7 +466,7 @@ void Session::DelJSONLocomotive(JSONParse *jp) { jout.Clear(); s = loco.name; jout.AddObject("locomotivedelete", s); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -479,7 +486,7 @@ void Session::SetJSONLocoDest(JSONParse *jp) { server->LocomotiveSetDest(loco, block, reverse); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -498,7 +505,7 @@ void Session::SetJSONLocoAssign(JSONParse *jp) { server->LocomotiveSetAssign(loco, block, reverse); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -514,7 +521,7 @@ void Session::SetJSONLocoReset(JSONParse *jp) { server->LocomotiveReset(loco); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -528,7 +535,7 @@ void Session::SetJSONLocoMan(JSONParse *jp) { server->LocomotiveSetMan(loco); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -542,7 +549,7 @@ void Session::SetJSONLocoAutoMan(JSONParse *jp) { server->LocomotiveSetAutoMan(loco); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -556,7 +563,7 @@ void Session::SetJSONLocoAuto(JSONParse *jp) { server->LocomotiveSetAuto(loco); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -570,7 +577,7 @@ void Session::SetJSONLocoAutoRand(JSONParse *jp) { server->LocomotiveSetAutoRand(loco); jout.Clear(); jout.AddObject("locomotive", server->LocomotiveGetJSON(loco)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -594,7 +601,7 @@ void Session::AddJSONTurnout(JSONParse *jp) { server->TurnoutChange(&to); jout.Clear(); jout.AddObject("turnout", server->TurnoutGetJSON(to.name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -620,7 +627,7 @@ void Session::DelJSONTurnout(JSONParse *jp) { jout.Clear(); s = to.name; jout.AddObject("turnoutdelete", s); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -646,7 +653,7 @@ void Session::SetJSONTurnout(JSONParse *jp) { server->TurnoutSet(name, active); jout.Clear(); jout.AddObject("turnout", server->TurnoutGetJSON(name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -670,7 +677,7 @@ void Session::AddJSONBlock(JSONParse *jp) { server->BlockChange(&bl); jout.Clear(); jout.AddObject("block", server->BlockGetJSON(bl.name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -696,7 +703,7 @@ void Session::DelJSONBlock(JSONParse *jp) { jout.Clear(); s = bl.name; jout.AddObject("blockdelete", s); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); } server->UnLockThread(); }; @@ -712,7 +719,7 @@ void Session::BlockJSONOff(JSONParse *jp) { jout.Clear(); jout.AddObject("block", server->BlockGetJSON(name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; @@ -727,7 +734,7 @@ void Session::BlockJSONClear(JSONParse *jp) { jout.Clear(); jout.AddObject("block", server->BlockGetJSON(name)); - if (network) network->_ChangeListPushToAll(jout.ToString()); + if (network) network->ChangeListPushToAll(jout.ToString()); server->UnLockThread(); }; diff --git a/webinterface/track.js b/webinterface/track.js index 1e9f616..c50d27c 100644 --- a/webinterface/track.js +++ b/webinterface/track.js @@ -143,6 +143,8 @@ function trackDrawElement(ctx, element, mode) { ctx.lineWidth = 2; ctx.setLineDash([0,0]); ctx.strokeStyle = modcol; + if (element.lockedby && element.lockedby != "") + ctx.strokeStyle = cssVar('--track-color-locked'); trackDrawTrack (ctx, {x: element.x, y: element.y}, element.dir); } else if (element.type == RAILWAY_CROSSING) { @@ -151,6 +153,8 @@ function trackDrawElement(ctx, element, mode) { ctx.lineWidth = 2; ctx.setLineDash([0,0]); ctx.strokeStyle = modcol; + if (element.lockedby && element.lockedby != "") + ctx.strokeStyle = cssVar('--track-color-locked'); trackDrawTrack (ctx, {x: element.x, y: element.y}, element.dir); trackDrawTrack (ctx, {x: element.x, y: element.y}, element.altdir); }