From b942ab58e18485f7a1ea316f081cf02b8edc7a1b Mon Sep 17 00:00:00 2001 From: rbiasini Date: Fri, 24 Aug 2018 19:45:33 -0700 Subject: [PATCH] fix critical put and get param that caused sporadic controlsd hanging (#333) * fix critical put and get param that caused sporadic controlsd hanging * test fix --- common/params.py | 53 +++++++++++++++++++++++---------- selfdrive/controls/controlsd.py | 6 ---- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/common/params.py b/common/params.py index 827cc21769..1036813eb9 100755 --- a/common/params.py +++ b/common/params.py @@ -263,23 +263,48 @@ class DBWriter(DBAccessor): self._lock = None +def read_db(params_path, key): + path = "%s/d/%s" % (params_path, key) + try: + with open(path, "rb") as f: + return f.read() + except IOError: + return None -class JSDB(object): - def __init__(self, fn): - self._fn = fn +def write_db(params_path, key, value): + lock = FileLock(params_path+"/.lock", True) + lock.acquire() - def begin(self, write=False): - if write: - return DBWriter(self._fn) - else: - return DBReader(self._fn) + try: + tmp_path = tempfile.mktemp(prefix=".tmp", dir=params_path) + with open(tmp_path, "wb") as f: + f.write(value) + f.flush() + os.fsync(f.fileno()) + + path = "%s/d/%s" % (params_path, key) + os.rename(tmp_path, path) + fsync_dir(os.path.dirname(path)) + finally: + lock.release() class Params(object): def __init__(self, db='/data/params'): - self.env = JSDB(db) + self.db = db + + # create the database if it doesn't exist... + if not os.path.exists(self.db+"/d"): + with self.transaction(write=True): + pass + + def transaction(self, write=False): + if write: + return DBWriter(self.db) + else: + return DBReader(self.db) def _clear_keys_with_type(self, tx_type): - with self.env.begin(write=True) as txn: + with self.transaction(write=True) as txn: for key in keys: if keys[key] == tx_type: txn.delete(key) @@ -291,7 +316,7 @@ class Params(object): self._clear_keys_with_type(TxType.CLEAR_ON_CAR_START) def delete(self, key): - with self.env.begin(write=True) as txn: + with self.transaction(write=True) as txn: txn.delete(key) def get(self, key, block=False): @@ -299,8 +324,7 @@ class Params(object): raise UnknownKeyName(key) while 1: - with self.env.begin() as txn: - ret = txn.get(key) + ret = read_db(self.db, key) if not block or ret is not None: break # is polling really the best we can do? @@ -311,8 +335,7 @@ class Params(object): if key not in keys: raise UnknownKeyName(key) - with self.env.begin(write=True) as txn: - txn.put(key, dat) + write_db(self.db, key, dat) if __name__ == "__main__": params = Params() diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 473f4504e4..ed2ae032fe 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -448,12 +448,6 @@ def controlsd_thread(gctx=None, rate=100, default_bias=0.): fcw_enabled = params.get("IsFcwEnabled") == "1" geofence = None - try: - from selfdrive.controls.lib.geofence import Geofence - geofence = Geofence(params.get("IsGeofenceEnabled") == "1") - except ImportError: - # geofence not available - params.put("IsGeofenceEnabled", "-1") PL = Planner(CP, fcw_enabled) LoC = LongControl(CP, CI.compute_gb)