Skip to content

Commit

Permalink
fix critical put and get param that caused sporadic controlsd hanging (
Browse files Browse the repository at this point in the history
…commaai#333)

* fix critical put and get param that caused sporadic controlsd hanging

* test fix
  • Loading branch information
rbiasini authored Aug 25, 2018
1 parent d18aefe commit 64ba1a7
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 21 deletions.
53 changes: 38 additions & 15 deletions common/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,23 +263,48 @@ def __exit__(self, type, value, traceback):
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)
Expand All @@ -291,16 +316,15 @@ def car_start(self):
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):
if key not in keys:
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?
Expand All @@ -311,8 +335,7 @@ def put(self, key, dat):
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()
Expand Down
6 changes: 0 additions & 6 deletions selfdrive/controls/controlsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 64ba1a7

Please sign in to comment.