[tor-commits] [nyx/master] Consistently use 'with' for locking

atagar at torproject.org atagar at torproject.org
Tue Sep 22 17:08:39 UTC 2015


commit d06cec4899bf0987c412afd7e8f55ad8045939d8
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Jul 4 13:10:52 2015 -0700

    Consistently use 'with' for locking
    
    As we've been rewriting components I've swapping locking to use the 'with'
    keyword (much safer, avoiding deadlocks in case of exceptions). Swapping the
    rest of the codebase over so we're consistent.
---
 nyx/config_panel.py           |  115 ++++++------
 nyx/connections/conn_panel.py |  304 +++++++++++++++---------------
 nyx/torrc_panel.py            |  268 +++++++++++++--------------
 nyx/util/tor_config.py        |  408 +++++++++++++++++++----------------------
 4 files changed, 524 insertions(+), 571 deletions(-)

diff --git a/nyx/config_panel.py b/nyx/config_panel.py
index 05a65e0..58f229b 100644
--- a/nyx/config_panel.py
+++ b/nyx/config_panel.py
@@ -332,14 +332,12 @@ class ConfigPanel(panel.Panel):
                  set ordering
     """
 
-    self.vals_lock.acquire()
-
-    if ordering:
-      CONFIG['features.config.order'] = ordering
+    with self.vals_lock:
+      if ordering:
+        CONFIG['features.config.order'] = ordering
 
-    self.conf_contents.sort(key=lambda i: (i.get_all(CONFIG['features.config.order'])))
-    self.conf_important_contents.sort(key=lambda i: (i.get_all(CONFIG['features.config.order'])))
-    self.vals_lock.release()
+      self.conf_contents.sort(key=lambda i: (i.get_all(CONFIG['features.config.order'])))
+      self.conf_important_contents.sort(key=lambda i: (i.get_all(CONFIG['features.config.order'])))
 
   def show_sort_dialog(self):
     """
@@ -573,78 +571,75 @@ class ConfigPanel(panel.Panel):
     ]
 
   def draw(self, width, height):
-    self.vals_lock.acquire()
-
-    # panel with details for the current selection
-
-    detail_panel_height = CONFIG['features.config.selectionDetails.height']
-    is_scrollbar_visible = False
+    with self.vals_lock:
+      # panel with details for the current selection
 
-    if detail_panel_height == 0 or detail_panel_height + 2 >= height:
-      # no detail panel
+      detail_panel_height = CONFIG['features.config.selectionDetails.height']
+      is_scrollbar_visible = False
 
-      detail_panel_height = 0
-      scroll_location = self.scroller.get_scroll_location(self._get_config_options(), height - 1)
-      cursor_selection = self.get_selection()
-      is_scrollbar_visible = len(self._get_config_options()) > height - 1
-    else:
-      # Shrink detail panel if there isn't sufficient room for the whole
-      # thing. The extra line is for the bottom border.
+      if detail_panel_height == 0 or detail_panel_height + 2 >= height:
+        # no detail panel
 
-      detail_panel_height = min(height - 1, detail_panel_height + 1)
-      scroll_location = self.scroller.get_scroll_location(self._get_config_options(), height - 1 - detail_panel_height)
-      cursor_selection = self.get_selection()
-      is_scrollbar_visible = len(self._get_config_options()) > height - detail_panel_height - 1
+        detail_panel_height = 0
+        scroll_location = self.scroller.get_scroll_location(self._get_config_options(), height - 1)
+        cursor_selection = self.get_selection()
+        is_scrollbar_visible = len(self._get_config_options()) > height - 1
+      else:
+        # Shrink detail panel if there isn't sufficient room for the whole
+        # thing. The extra line is for the bottom border.
 
-      if cursor_selection is not None:
-        self._draw_selection_panel(cursor_selection, width, detail_panel_height, is_scrollbar_visible)
+        detail_panel_height = min(height - 1, detail_panel_height + 1)
+        scroll_location = self.scroller.get_scroll_location(self._get_config_options(), height - 1 - detail_panel_height)
+        cursor_selection = self.get_selection()
+        is_scrollbar_visible = len(self._get_config_options()) > height - detail_panel_height - 1
 
-    # draws the top label
+        if cursor_selection is not None:
+          self._draw_selection_panel(cursor_selection, width, detail_panel_height, is_scrollbar_visible)
 
-    if self.is_title_visible():
-      config_type = 'Tor' if self.config_type == State.TOR else 'Arm'
-      hidden_msg = "press 'a' to hide most options" if self.show_all else "press 'a' to show all options"
-      title_label = '%s Configuration (%s):' % (config_type, hidden_msg)
-      self.addstr(0, 0, title_label, curses.A_STANDOUT)
+      # draws the top label
 
-    # draws left-hand scroll bar if content's longer than the height
+      if self.is_title_visible():
+        config_type = 'Tor' if self.config_type == State.TOR else 'Arm'
+        hidden_msg = "press 'a' to hide most options" if self.show_all else "press 'a' to show all options"
+        title_label = '%s Configuration (%s):' % (config_type, hidden_msg)
+        self.addstr(0, 0, title_label, curses.A_STANDOUT)
 
-    scroll_offset = 1
+      # draws left-hand scroll bar if content's longer than the height
 
-    if is_scrollbar_visible:
-      scroll_offset = 3
-      self.add_scroll_bar(scroll_location, scroll_location + height - detail_panel_height - 1, len(self._get_config_options()), 1 + detail_panel_height)
+      scroll_offset = 1
 
-    option_width = CONFIG['features.config.state.colWidth.option']
-    value_width = CONFIG['features.config.state.colWidth.value']
-    description_width = max(0, width - scroll_offset - option_width - value_width - 2)
+      if is_scrollbar_visible:
+        scroll_offset = 3
+        self.add_scroll_bar(scroll_location, scroll_location + height - detail_panel_height - 1, len(self._get_config_options()), 1 + detail_panel_height)
 
-    # if the description column is overly long then use its space for the
-    # value instead
+      option_width = CONFIG['features.config.state.colWidth.option']
+      value_width = CONFIG['features.config.state.colWidth.value']
+      description_width = max(0, width - scroll_offset - option_width - value_width - 2)
 
-    if description_width > 80:
-      value_width += description_width - 80
-      description_width = 80
+      # if the description column is overly long then use its space for the
+      # value instead
 
-    for line_number in range(scroll_location, len(self._get_config_options())):
-      entry = self._get_config_options()[line_number]
-      draw_line = line_number + detail_panel_height + 1 - scroll_location
+      if description_width > 80:
+        value_width += description_width - 80
+        description_width = 80
 
-      line_format = [curses.A_NORMAL if entry.get(Field.IS_DEFAULT) else curses.A_BOLD]
+      for line_number in range(scroll_location, len(self._get_config_options())):
+        entry = self._get_config_options()[line_number]
+        draw_line = line_number + detail_panel_height + 1 - scroll_location
 
-      if entry.get(Field.CATEGORY):
-        line_format += [CATEGORY_COLOR[entry.get(Field.CATEGORY)]]
+        line_format = [curses.A_NORMAL if entry.get(Field.IS_DEFAULT) else curses.A_BOLD]
 
-      if entry == cursor_selection:
-        line_format += [curses.A_STANDOUT]
+        if entry.get(Field.CATEGORY):
+          line_format += [CATEGORY_COLOR[entry.get(Field.CATEGORY)]]
 
-      line_text = entry.get_label(option_width, value_width, description_width)
-      self.addstr(draw_line, scroll_offset, line_text, *line_format)
+        if entry == cursor_selection:
+          line_format += [curses.A_STANDOUT]
 
-      if draw_line >= height:
-        break
+        line_text = entry.get_label(option_width, value_width, description_width)
+        self.addstr(draw_line, scroll_offset, line_text, *line_format)
 
-    self.vals_lock.release()
+        if draw_line >= height:
+          break
 
   def _get_config_options(self):
     return self.conf_contents if self.show_all else self.conf_important_contents
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index 0a27721..1402b71 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -148,10 +148,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
     time we were last paused.
     """
 
-    if self._halt_time:
-      return self._halt_time
-    else:
-      return panel.Panel.get_pause_time(self)
+    return self._halt_time if self._halt_time else panel.Panel.get_pause_time(self)
 
   def set_sort_order(self, ordering = None):
     """
@@ -162,22 +159,19 @@ class ConnectionPanel(panel.Panel, threading.Thread):
                  set ordering
     """
 
-    self.vals_lock.acquire()
-
-    if ordering:
-      nyx_config = conf.get_config('nyx')
-
-      ordering_keys = [entries.SortAttr.keys()[entries.SortAttr.index_of(v)] for v in ordering]
-      nyx_config.set('features.connection.order', ', '.join(ordering_keys))
+    with self.vals_lock:
+      if ordering:
+        nyx_config = conf.get_config('nyx')
 
-    self._entries.sort(key = lambda i: (i.get_sort_values(CONFIG['features.connection.order'], self.get_listing_type())))
+        ordering_keys = [entries.SortAttr.keys()[entries.SortAttr.index_of(v)] for v in ordering]
+        nyx_config.set('features.connection.order', ', '.join(ordering_keys))
 
-    self._entry_lines = []
+      self._entries.sort(key = lambda i: (i.get_sort_values(CONFIG['features.connection.order'], self.get_listing_type())))
 
-    for entry in self._entries:
-      self._entry_lines += entry.getLines()
+      self._entry_lines = []
 
-    self.vals_lock.release()
+      for entry in self._entries:
+        self._entry_lines += entry.getLines()
 
   def get_listing_type(self):
     """
@@ -197,17 +191,14 @@ class ConnectionPanel(panel.Panel, threading.Thread):
     if self.get_listing_type() == listing_type:
       return
 
-    self.vals_lock.acquire()
-
-    nyx_config = conf.get_config('nyx')
-    nyx_config.set('features.connection.listing_type', Listing.keys()[Listing.index_of(listing_type)])
-
-    # if we're sorting by the listing then we need to resort
+    with self.vals_lock:
+      nyx_config = conf.get_config('nyx')
+      nyx_config.set('features.connection.listing_type', Listing.keys()[Listing.index_of(listing_type)])
 
-    if entries.SortAttr.LISTING in CONFIG['features.connection.order']:
-      self.set_sort_order()
+      # if we're sorting by the listing then we need to resort
 
-    self.vals_lock.release()
+      if entries.SortAttr.LISTING in CONFIG['features.connection.order']:
+        self.set_sort_order()
 
   def is_clients_allowed(self):
     """
@@ -423,86 +414,83 @@ class ConnectionPanel(panel.Panel, threading.Thread):
     return self._scroller.get_cursor_selection(self._entry_lines)
 
   def draw(self, width, height):
-    self.vals_lock.acquire()
-
-    # if we don't have any contents then refuse to show details
-
-    if not self._entries:
-      self._show_details = False
+    with self.vals_lock:
+      # if we don't have any contents then refuse to show details
 
-    # extra line when showing the detail panel is for the bottom border
+      if not self._entries:
+        self._show_details = False
 
-    detail_panel_offset = DETAILS_HEIGHT + 1 if self._show_details else 0
-    is_scrollbar_visible = len(self._entry_lines) > height - detail_panel_offset - 1
+      # extra line when showing the detail panel is for the bottom border
 
-    scroll_location = self._scroller.get_scroll_location(self._entry_lines, height - detail_panel_offset - 1)
-    cursor_selection = self.get_selection()
+      detail_panel_offset = DETAILS_HEIGHT + 1 if self._show_details else 0
+      is_scrollbar_visible = len(self._entry_lines) > height - detail_panel_offset - 1
 
-    # draws the detail panel if currently displaying it
+      scroll_location = self._scroller.get_scroll_location(self._entry_lines, height - detail_panel_offset - 1)
+      cursor_selection = self.get_selection()
 
-    if self._show_details and cursor_selection:
-      # This is a solid border unless the scrollbar is visible, in which case a
-      # 'T' pipe connects the border to the bar.
+      # draws the detail panel if currently displaying it
 
-      ui_tools.draw_box(self, 0, 0, width, DETAILS_HEIGHT + 2)
+      if self._show_details and cursor_selection:
+        # This is a solid border unless the scrollbar is visible, in which case a
+        # 'T' pipe connects the border to the bar.
 
-      if is_scrollbar_visible:
-        self.addch(DETAILS_HEIGHT + 1, 1, curses.ACS_TTEE)
+        ui_tools.draw_box(self, 0, 0, width, DETAILS_HEIGHT + 2)
 
-      draw_entries = cursor_selection.get_details(width)
+        if is_scrollbar_visible:
+          self.addch(DETAILS_HEIGHT + 1, 1, curses.ACS_TTEE)
 
-      for i in range(min(len(draw_entries), DETAILS_HEIGHT)):
-        self.addstr(1 + i, 2, draw_entries[i][0], *draw_entries[i][1])
+        draw_entries = cursor_selection.get_details(width)
 
-    # title label with connection counts
+        for i in range(min(len(draw_entries), DETAILS_HEIGHT)):
+          self.addstr(1 + i, 2, draw_entries[i][0], *draw_entries[i][1])
 
-    if self.is_title_visible():
-      title = 'Connection Details:' if self._show_details else self._title
-      self.addstr(0, 0, title, curses.A_STANDOUT)
+      # title label with connection counts
 
-    scroll_offset = 0
+      if self.is_title_visible():
+        title = 'Connection Details:' if self._show_details else self._title
+        self.addstr(0, 0, title, curses.A_STANDOUT)
 
-    if is_scrollbar_visible:
-      scroll_offset = 2
-      self.add_scroll_bar(scroll_location, scroll_location + height - detail_panel_offset - 1, len(self._entry_lines), 1 + detail_panel_offset)
+      scroll_offset = 0
 
-    if self.is_paused() or not self._is_tor_running:
-      current_time = self.get_pause_time()
-    else:
-      current_time = time.time()
+      if is_scrollbar_visible:
+        scroll_offset = 2
+        self.add_scroll_bar(scroll_location, scroll_location + height - detail_panel_offset - 1, len(self._entry_lines), 1 + detail_panel_offset)
 
-    for line_number in range(scroll_location, len(self._entry_lines)):
-      entry_line = self._entry_lines[line_number]
+      if self.is_paused() or not self._is_tor_running:
+        current_time = self.get_pause_time()
+      else:
+        current_time = time.time()
 
-      # if this is an unresolved SOCKS, HIDDEN, or CONTROL entry then queue up
-      # resolution for the applicaitions they belong to
+      for line_number in range(scroll_location, len(self._entry_lines)):
+        entry_line = self._entry_lines[line_number]
 
-      if isinstance(entry_line, conn_entry.ConnectionLine) and entry_line.is_unresolved_application():
-        self._resolve_apps()
+        # if this is an unresolved SOCKS, HIDDEN, or CONTROL entry then queue up
+        # resolution for the applicaitions they belong to
 
-      # hilighting if this is the selected line
+        if isinstance(entry_line, conn_entry.ConnectionLine) and entry_line.is_unresolved_application():
+          self._resolve_apps()
 
-      extra_format = curses.A_STANDOUT if entry_line == cursor_selection else curses.A_NORMAL
+        # hilighting if this is the selected line
 
-      draw_line = line_number + detail_panel_offset + 1 - scroll_location
+        extra_format = curses.A_STANDOUT if entry_line == cursor_selection else curses.A_NORMAL
 
-      prefix = entry_line.get_listing_prefix()
+        draw_line = line_number + detail_panel_offset + 1 - scroll_location
 
-      for i in range(len(prefix)):
-        self.addch(draw_line, scroll_offset + i, prefix[i])
+        prefix = entry_line.get_listing_prefix()
 
-      x_offset = scroll_offset + len(prefix)
-      draw_entry = entry_line.get_listing_entry(width - scroll_offset - len(prefix), current_time, self.get_listing_type())
+        for i in range(len(prefix)):
+          self.addch(draw_line, scroll_offset + i, prefix[i])
 
-      for msg, attr in draw_entry:
-        attr |= extra_format
-        self.addstr(draw_line, x_offset, msg, attr)
-        x_offset += len(msg)
+        x_offset = scroll_offset + len(prefix)
+        draw_entry = entry_line.get_listing_entry(width - scroll_offset - len(prefix), current_time, self.get_listing_type())
 
-      if draw_line >= height:
-        break
+        for msg, attr in draw_entry:
+          attr |= extra_format
+          self.addstr(draw_line, x_offset, msg, attr)
+          x_offset += len(msg)
 
-    self.vals_lock.release()
+        if draw_line >= height:
+          break
 
   def stop(self):
     """
@@ -528,114 +516,112 @@ class ConnectionPanel(panel.Panel, threading.Thread):
     conn_resolver = nyx.util.tracker.get_connection_tracker()
     current_resolution_count = conn_resolver.run_counter()
 
-    self.vals_lock.acquire()
-
-    new_entries = []  # the new results we'll display
+    with self.vals_lock:
+      new_entries = []  # the new results we'll display
 
-    # Fetches new connections and client circuits...
-    # new_connections  [(local ip, local port, foreign ip, foreign port)...]
-    # new_circuits     {circuit_id => (status, purpose, path)...}
+      # Fetches new connections and client circuits...
+      # new_connections  [(local ip, local port, foreign ip, foreign port)...]
+      # new_circuits     {circuit_id => (status, purpose, path)...}
 
-    new_connections = [(conn.local_address, conn.local_port, conn.remote_address, conn.remote_port) for conn in conn_resolver.get_value()]
-    new_circuits = {}
+      new_connections = [(conn.local_address, conn.local_port, conn.remote_address, conn.remote_port) for conn in conn_resolver.get_value()]
+      new_circuits = {}
 
-    for circ in tor_controller().get_circuits([]):
-      # Skips established single-hop circuits (these are for directory
-      # fetches, not client circuits)
+      for circ in tor_controller().get_circuits([]):
+        # Skips established single-hop circuits (these are for directory
+        # fetches, not client circuits)
 
-      if not (circ.status == 'BUILT' and len(circ.path) == 1):
-        new_circuits[circ.id] = (circ.status, circ.purpose, [entry[0] for entry in circ.path])
+        if not (circ.status == 'BUILT' and len(circ.path) == 1):
+          new_circuits[circ.id] = (circ.status, circ.purpose, [entry[0] for entry in circ.path])
 
-    # Populates new_entries with any of our old entries that still exist.
-    # This is both for performance and to keep from resetting the uptime
-    # attributes. Note that CircEntries are a ConnectionEntry subclass so
-    # we need to check for them first.
+      # Populates new_entries with any of our old entries that still exist.
+      # This is both for performance and to keep from resetting the uptime
+      # attributes. Note that CircEntries are a ConnectionEntry subclass so
+      # we need to check for them first.
 
-    for old_entry in self._entries:
-      if isinstance(old_entry, circ_entry.CircEntry):
-        new_entry = new_circuits.get(old_entry.circuit_id)
+      for old_entry in self._entries:
+        if isinstance(old_entry, circ_entry.CircEntry):
+          new_entry = new_circuits.get(old_entry.circuit_id)
 
-        if new_entry:
-          old_entry.update(new_entry[0], new_entry[2])
-          new_entries.append(old_entry)
-          del new_circuits[old_entry.circuit_id]
-      elif isinstance(old_entry, conn_entry.ConnectionEntry):
-        connection_line = old_entry.getLines()[0]
-        conn_attr = (connection_line.local.get_address(), connection_line.local.get_port(),
-                     connection_line.foreign.get_address(), connection_line.foreign.get_port())
+          if new_entry:
+            old_entry.update(new_entry[0], new_entry[2])
+            new_entries.append(old_entry)
+            del new_circuits[old_entry.circuit_id]
+        elif isinstance(old_entry, conn_entry.ConnectionEntry):
+          connection_line = old_entry.getLines()[0]
+          conn_attr = (connection_line.local.get_address(), connection_line.local.get_port(),
+                       connection_line.foreign.get_address(), connection_line.foreign.get_port())
 
-        if conn_attr in new_connections:
-          new_entries.append(old_entry)
-          new_connections.remove(conn_attr)
+          if conn_attr in new_connections:
+            new_entries.append(old_entry)
+            new_connections.remove(conn_attr)
 
-    # Reset any display attributes for the entries we're keeping
+      # Reset any display attributes for the entries we're keeping
 
-    for entry in new_entries:
-      entry.reset_display()
+      for entry in new_entries:
+        entry.reset_display()
 
-    # Adds any new connection and circuit entries.
+      # Adds any new connection and circuit entries.
 
-    for local_address, local_port, remote_address, remote_port in new_connections:
-      new_conn_entry = conn_entry.ConnectionEntry(local_address, local_port, remote_address, remote_port)
-      new_conn_line = new_conn_entry.getLines()[0]
+      for local_address, local_port, remote_address, remote_port in new_connections:
+        new_conn_entry = conn_entry.ConnectionEntry(local_address, local_port, remote_address, remote_port)
+        new_conn_line = new_conn_entry.getLines()[0]
 
-      if new_conn_line.get_type() != conn_entry.Category.CIRCUIT:
-        new_entries.append(new_conn_entry)
+        if new_conn_line.get_type() != conn_entry.Category.CIRCUIT:
+          new_entries.append(new_conn_entry)
 
-        # updates exit port and client locale usage information
-        if new_conn_line.is_private():
-          if new_conn_line.get_type() == conn_entry.Category.INBOUND:
-            # client connection, update locale information
+          # updates exit port and client locale usage information
+          if new_conn_line.is_private():
+            if new_conn_line.get_type() == conn_entry.Category.INBOUND:
+              # client connection, update locale information
 
-            client_locale = new_conn_line.foreign.get_locale()
+              client_locale = new_conn_line.foreign.get_locale()
 
-            if client_locale:
-              self._client_locale_usage[client_locale] = self._client_locale_usage.get(client_locale, 0) + 1
-          elif new_conn_line.get_type() == conn_entry.Category.EXIT:
-            exit_port = new_conn_line.foreign.get_port()
-            self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1
+              if client_locale:
+                self._client_locale_usage[client_locale] = self._client_locale_usage.get(client_locale, 0) + 1
+            elif new_conn_line.get_type() == conn_entry.Category.EXIT:
+              exit_port = new_conn_line.foreign.get_port()
+              self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1
 
-    for circuit_id in new_circuits:
-      status, purpose, path = new_circuits[circuit_id]
-      new_entries.append(circ_entry.CircEntry(circuit_id, status, purpose, path))
+      for circuit_id in new_circuits:
+        status, purpose, path = new_circuits[circuit_id]
+        new_entries.append(circ_entry.CircEntry(circuit_id, status, purpose, path))
 
-    # Counts the relays in each of the categories. This also flushes the
-    # type cache for all of the connections (in case its changed since last
-    # fetched).
+      # Counts the relays in each of the categories. This also flushes the
+      # type cache for all of the connections (in case its changed since last
+      # fetched).
 
-    category_types = list(conn_entry.Category)
-    type_counts = dict((type, 0) for type in category_types)
+      category_types = list(conn_entry.Category)
+      type_counts = dict((type, 0) for type in category_types)
 
-    for entry in new_entries:
-      if isinstance(entry, conn_entry.ConnectionEntry):
-        type_counts[entry.getLines()[0].get_type()] += 1
-      elif isinstance(entry, circ_entry.CircEntry):
-        type_counts[conn_entry.Category.CIRCUIT] += 1
+      for entry in new_entries:
+        if isinstance(entry, conn_entry.ConnectionEntry):
+          type_counts[entry.getLines()[0].get_type()] += 1
+        elif isinstance(entry, circ_entry.CircEntry):
+          type_counts[conn_entry.Category.CIRCUIT] += 1
 
-    # makes labels for all the categories with connections (ie,
-    # "21 outbound", "1 control", etc)
+      # makes labels for all the categories with connections (ie,
+      # "21 outbound", "1 control", etc)
 
-    count_labels = []
+      count_labels = []
 
-    for category in category_types:
-      if type_counts[category] > 0:
-        count_labels.append('%i %s' % (type_counts[category], category.lower()))
+      for category in category_types:
+        if type_counts[category] > 0:
+          count_labels.append('%i %s' % (type_counts[category], category.lower()))
 
-    if count_labels:
-      self._title = 'Connections (%s):' % ', '.join(count_labels)
-    else:
-      self._title = 'Connections:'
+      if count_labels:
+        self._title = 'Connections (%s):' % ', '.join(count_labels)
+      else:
+        self._title = 'Connections:'
 
-    self._entries = new_entries
+      self._entries = new_entries
 
-    self._entry_lines = []
+      self._entry_lines = []
 
-    for entry in self._entries:
-      self._entry_lines += entry.getLines()
+      for entry in self._entries:
+        self._entry_lines += entry.getLines()
 
-    self.set_sort_order()
-    self._last_resource_fetch = current_resolution_count
-    self.vals_lock.release()
+      self.set_sort_order()
+      self._last_resource_fetch = current_resolution_count
 
   def _resolve_apps(self, flag_query = True):
     """
diff --git a/nyx/torrc_panel.py b/nyx/torrc_panel.py
index dd84fb3..0ed0b96 100644
--- a/nyx/torrc_panel.py
+++ b/nyx/torrc_panel.py
@@ -160,192 +160,188 @@ class TorrcPanel(panel.Panel):
     ]
 
   def draw(self, width, height):
-    self.vals_lock.acquire()
-
-    # If true, we assume that the cached value in self._last_content_height is
-    # still accurate, and stop drawing when there's nothing more to display.
-    # Otherwise the self._last_content_height is suspect, and we'll process all
-    # the content to check if it's right (and redraw again with the corrected
-    # height if not).
-
-    trust_last_content_height = self._last_content_height_args == (width, height)
+    with self.vals_lock:
+      # If true, we assume that the cached value in self._last_content_height is
+      # still accurate, and stop drawing when there's nothing more to display.
+      # Otherwise the self._last_content_height is suspect, and we'll process all
+      # the content to check if it's right (and redraw again with the corrected
+      # height if not).
 
-    # restricts scroll location to valid bounds
+      trust_last_content_height = self._last_content_height_args == (width, height)
 
-    self.scroll = max(0, min(self.scroll, self._last_content_height - height + 1))
+      # restricts scroll location to valid bounds
 
-    rendered_contents, corrections, conf_location = None, {}, None
+      self.scroll = max(0, min(self.scroll, self._last_content_height - height + 1))
 
-    if self.config_type == Config.TORRC:
-      loaded_torrc = tor_config.get_torrc()
-      loaded_torrc.get_lock().acquire()
-      conf_location = loaded_torrc.get_config_location()
+      rendered_contents, corrections, conf_location = None, {}, None
 
-      if not loaded_torrc.is_loaded():
-        rendered_contents = ['### Unable to load the torrc ###']
-      else:
-        rendered_contents = loaded_torrc.get_display_contents(self.strip_comments)
+      if self.config_type == Config.TORRC:
+        loaded_torrc = tor_config.get_torrc()
 
-        # constructs a mapping of line numbers to the issue on it
+        with loaded_torrc.get_lock():
+          conf_location = loaded_torrc.get_config_location()
 
-        corrections = dict((line_number, (issue, msg)) for line_number, issue, msg in loaded_torrc.get_corrections())
+          if not loaded_torrc.is_loaded():
+            rendered_contents = ['### Unable to load the torrc ###']
+          else:
+            rendered_contents = loaded_torrc.get_display_contents(self.strip_comments)
 
-      loaded_torrc.get_lock().release()
-    else:
-      loaded_nyxrc = conf.get_config('nyx')
-      conf_location = loaded_nyxrc._path
-      rendered_contents = list(loaded_nyxrc._raw_contents)
+            # constructs a mapping of line numbers to the issue on it
 
-    # offset to make room for the line numbers
+            corrections = dict((line_number, (issue, msg)) for line_number, issue, msg in loaded_torrc.get_corrections())
+      else:
+        loaded_nyxrc = conf.get_config('nyx')
+        conf_location = loaded_nyxrc._path
+        rendered_contents = list(loaded_nyxrc._raw_contents)
 
-    line_number_offset = 0
+      # offset to make room for the line numbers
 
-    if self.show_line_num:
-      if len(rendered_contents) == 0:
-        line_number_offset = 2
-      else:
-        line_number_offset = int(math.log10(len(rendered_contents))) + 2
+      line_number_offset = 0
 
-    # draws left-hand scroll bar if content's longer than the height
+      if self.show_line_num:
+        if len(rendered_contents) == 0:
+          line_number_offset = 2
+        else:
+          line_number_offset = int(math.log10(len(rendered_contents))) + 2
 
-    scroll_offset = 0
+      # draws left-hand scroll bar if content's longer than the height
 
-    if CONFIG['features.config.file.showScrollbars'] and self._last_content_height > height - 1:
-      scroll_offset = 3
-      self.add_scroll_bar(self.scroll, self.scroll + height - 1, self._last_content_height, 1)
+      scroll_offset = 0
 
-    display_line = -self.scroll + 1  # line we're drawing on
+      if CONFIG['features.config.file.showScrollbars'] and self._last_content_height > height - 1:
+        scroll_offset = 3
+        self.add_scroll_bar(self.scroll, self.scroll + height - 1, self._last_content_height, 1)
 
-    # draws the top label
+      display_line = -self.scroll + 1  # line we're drawing on
 
-    if self.is_title_visible():
-      source_label = 'Tor' if self.config_type == Config.TORRC else 'Nyx'
-      location_label = ' (%s)' % conf_location if conf_location else ''
-      self.addstr(0, 0, '%s Configuration File%s:' % (source_label, location_label), curses.A_STANDOUT)
+      # draws the top label
 
-    is_multiline = False  # true if we're in the middle of a multiline torrc entry
+      if self.is_title_visible():
+        source_label = 'Tor' if self.config_type == Config.TORRC else 'Nyx'
+        location_label = ' (%s)' % conf_location if conf_location else ''
+        self.addstr(0, 0, '%s Configuration File%s:' % (source_label, location_label), curses.A_STANDOUT)
 
-    for line_number in range(0, len(rendered_contents)):
-      line_text = rendered_contents[line_number]
-      line_text = line_text.rstrip()  # remove ending whitespace
+      is_multiline = False  # true if we're in the middle of a multiline torrc entry
 
-      # blank lines are hidden when stripping comments
+      for line_number in range(0, len(rendered_contents)):
+        line_text = rendered_contents[line_number]
+        line_text = line_text.rstrip()  # remove ending whitespace
 
-      if self.strip_comments and not line_text:
-        continue
+        # blank lines are hidden when stripping comments
 
-      # splits the line into its component (msg, format) tuples
+        if self.strip_comments and not line_text:
+          continue
 
-      line_comp = {
-        'option': ['', (curses.A_BOLD, 'green')],
-        'argument': ['', (curses.A_BOLD, 'cyan')],
-        'correction': ['', (curses.A_BOLD, 'cyan')],
-        'comment': ['', ('white',)],
-      }
+        # splits the line into its component (msg, format) tuples
 
-      # parses the comment
+        line_comp = {
+          'option': ['', (curses.A_BOLD, 'green')],
+          'argument': ['', (curses.A_BOLD, 'cyan')],
+          'correction': ['', (curses.A_BOLD, 'cyan')],
+          'comment': ['', ('white',)],
+        }
 
-      comment_index = line_text.find('#')
+        # parses the comment
 
-      if comment_index != -1:
-        line_comp['comment'][0] = line_text[comment_index:]
-        line_text = line_text[:comment_index]
+        comment_index = line_text.find('#')
 
-      # splits the option and argument, preserving any whitespace around them
+        if comment_index != -1:
+          line_comp['comment'][0] = line_text[comment_index:]
+          line_text = line_text[:comment_index]
 
-      stripped_line = line_text.strip()
-      option_index = stripped_line.find(' ')
+        # splits the option and argument, preserving any whitespace around them
 
-      if is_multiline:
-        # part of a multiline entry started on a previous line so everything
-        # is part of the argument
-        line_comp['argument'][0] = line_text
-      elif option_index == -1:
-        # no argument provided
-        line_comp['option'][0] = line_text
-      else:
-        option_text = stripped_line[:option_index]
-        option_end = line_text.find(option_text) + len(option_text)
-        line_comp['option'][0] = line_text[:option_end]
-        line_comp['argument'][0] = line_text[option_end:]
+        stripped_line = line_text.strip()
+        option_index = stripped_line.find(' ')
 
-      # flags following lines as belonging to this multiline entry if it ends
-      # with a slash
+        if is_multiline:
+          # part of a multiline entry started on a previous line so everything
+          # is part of the argument
+          line_comp['argument'][0] = line_text
+        elif option_index == -1:
+          # no argument provided
+          line_comp['option'][0] = line_text
+        else:
+          option_text = stripped_line[:option_index]
+          option_end = line_text.find(option_text) + len(option_text)
+          line_comp['option'][0] = line_text[:option_end]
+          line_comp['argument'][0] = line_text[option_end:]
 
-      if stripped_line:
-        is_multiline = stripped_line.endswith('\\')
+        # flags following lines as belonging to this multiline entry if it ends
+        # with a slash
 
-      # gets the correction
+        if stripped_line:
+          is_multiline = stripped_line.endswith('\\')
 
-      if line_number in corrections:
-        line_issue, line_issue_msg = corrections[line_number]
+        # gets the correction
 
-        if line_issue in (tor_config.ValidationError.DUPLICATE, tor_config.ValidationError.IS_DEFAULT):
-          line_comp['option'][1] = (curses.A_BOLD, 'blue')
-          line_comp['argument'][1] = (curses.A_BOLD, 'blue')
-        elif line_issue == tor_config.ValidationError.MISMATCH:
-          line_comp['argument'][1] = (curses.A_BOLD, 'red')
-          line_comp['correction'][0] = ' (%s)' % line_issue_msg
-        else:
-          # For some types of configs the correction field is simply used to
-          # provide extra data (for instance, the type for tor state fields).
+        if line_number in corrections:
+          line_issue, line_issue_msg = corrections[line_number]
 
-          line_comp['correction'][0] = ' (%s)' % line_issue_msg
-          line_comp['correction'][1] = (curses.A_BOLD, 'magenta')
+          if line_issue in (tor_config.ValidationError.DUPLICATE, tor_config.ValidationError.IS_DEFAULT):
+            line_comp['option'][1] = (curses.A_BOLD, 'blue')
+            line_comp['argument'][1] = (curses.A_BOLD, 'blue')
+          elif line_issue == tor_config.ValidationError.MISMATCH:
+            line_comp['argument'][1] = (curses.A_BOLD, 'red')
+            line_comp['correction'][0] = ' (%s)' % line_issue_msg
+          else:
+            # For some types of configs the correction field is simply used to
+            # provide extra data (for instance, the type for tor state fields).
 
-      # draws the line number
+            line_comp['correction'][0] = ' (%s)' % line_issue_msg
+            line_comp['correction'][1] = (curses.A_BOLD, 'magenta')
 
-      if self.show_line_num and display_line < height and display_line >= 1:
-        line_number_str = ('%%%ii' % (line_number_offset - 1)) % (line_number + 1)
-        self.addstr(display_line, scroll_offset, line_number_str, curses.A_BOLD, 'yellow')
+        # draws the line number
 
-      # draws the rest of the components with line wrap
+        if self.show_line_num and display_line < height and display_line >= 1:
+          line_number_str = ('%%%ii' % (line_number_offset - 1)) % (line_number + 1)
+          self.addstr(display_line, scroll_offset, line_number_str, curses.A_BOLD, 'yellow')
 
-      cursor_location, line_offset = line_number_offset + scroll_offset, 0
-      max_lines_per_entry = CONFIG['features.config.file.max_lines_per_entry']
-      display_queue = [line_comp[entry] for entry in ('option', 'argument', 'correction', 'comment')]
+        # draws the rest of the components with line wrap
 
-      while display_queue:
-        msg, format = display_queue.pop(0)
+        cursor_location, line_offset = line_number_offset + scroll_offset, 0
+        max_lines_per_entry = CONFIG['features.config.file.max_lines_per_entry']
+        display_queue = [line_comp[entry] for entry in ('option', 'argument', 'correction', 'comment')]
 
-        max_msg_size, include_break = width - cursor_location, False
+        while display_queue:
+          msg, format = display_queue.pop(0)
 
-        if len(msg) >= max_msg_size:
-          # message is too long - break it up
+          max_msg_size, include_break = width - cursor_location, False
 
-          if line_offset == max_lines_per_entry - 1:
-            msg = str_tools.crop(msg, max_msg_size)
-          else:
-            include_break = True
-            msg, remainder = str_tools.crop(msg, max_msg_size, 4, 4, str_tools.Ending.HYPHEN, True)
-            display_queue.insert(0, (remainder.strip(), format))
+          if len(msg) >= max_msg_size:
+            # message is too long - break it up
 
-        draw_line = display_line + line_offset
+            if line_offset == max_lines_per_entry - 1:
+              msg = str_tools.crop(msg, max_msg_size)
+            else:
+              include_break = True
+              msg, remainder = str_tools.crop(msg, max_msg_size, 4, 4, str_tools.Ending.HYPHEN, True)
+              display_queue.insert(0, (remainder.strip(), format))
 
-        if msg and draw_line < height and draw_line >= 1:
-          self.addstr(draw_line, cursor_location, msg, *format)
+          draw_line = display_line + line_offset
 
-        # If we're done, and have added content to this line, then start
-        # further content on the next line.
+          if msg and draw_line < height and draw_line >= 1:
+            self.addstr(draw_line, cursor_location, msg, *format)
 
-        cursor_location += len(msg)
-        include_break |= not display_queue and cursor_location != line_number_offset + scroll_offset
+          # If we're done, and have added content to this line, then start
+          # further content on the next line.
 
-        if include_break:
-          line_offset += 1
-          cursor_location = line_number_offset + scroll_offset
+          cursor_location += len(msg)
+          include_break |= not display_queue and cursor_location != line_number_offset + scroll_offset
 
-      display_line += max(line_offset, 1)
+          if include_break:
+            line_offset += 1
+            cursor_location = line_number_offset + scroll_offset
 
-      if trust_last_content_height and display_line >= height:
-        break
+        display_line += max(line_offset, 1)
 
-    if not trust_last_content_height:
-      self._last_content_height_args = (width, height)
-      new_content_height = display_line + self.scroll - 1
+        if trust_last_content_height and display_line >= height:
+          break
 
-      if self._last_content_height != new_content_height:
-        self._last_content_height = new_content_height
-        self.redraw(True)
+      if not trust_last_content_height:
+        self._last_content_height_args = (width, height)
+        new_content_height = display_line + self.scroll - 1
 
-    self.vals_lock.release()
+        if self._last_content_height != new_content_height:
+          self._last_content_height = new_content_height
+          self.redraw(True)
diff --git a/nyx/util/tor_config.py b/nyx/util/tor_config.py
index 4e3f16e..35ebd24 100644
--- a/nyx/util/tor_config.py
+++ b/nyx/util/tor_config.py
@@ -149,170 +149,168 @@ def load_option_descriptions(load_path = None, check_version = True):
                    match the cached descriptors, otherwise accepts anyway
   """
 
-  CONFIG_DESCRIPTIONS_LOCK.acquire()
-  CONFIG_DESCRIPTIONS.clear()
+  with CONFIG_DESCRIPTIONS_LOCK:
+    CONFIG_DESCRIPTIONS.clear()
 
-  raised_exc = None
-  loaded_version = ''
+    raised_exc = None
+    loaded_version = ''
 
-  try:
-    if load_path:
-      # Input file is expected to be of the form:
-      # <option>
-      # <arg description>
-      # <description, possibly multiple lines>
-      # <PERSIST_ENTRY_DIVIDER>
-      input_file = open(load_path, 'r')
-      input_file_contents = input_file.readlines()
-      input_file.close()
+    try:
+      if load_path:
+        # Input file is expected to be of the form:
+        # <option>
+        # <arg description>
+        # <description, possibly multiple lines>
+        # <PERSIST_ENTRY_DIVIDER>
+        input_file = open(load_path, 'r')
+        input_file_contents = input_file.readlines()
+        input_file.close()
 
-      try:
-        version_line = input_file_contents.pop(0).rstrip()
+        try:
+          version_line = input_file_contents.pop(0).rstrip()
 
-        if version_line.startswith('Tor Version '):
-          file_version = version_line[12:]
-          loaded_version = file_version
-          tor_version = tor_controller().get_info('version', '')
+          if version_line.startswith('Tor Version '):
+            file_version = version_line[12:]
+            loaded_version = file_version
+            tor_version = tor_controller().get_info('version', '')
 
-          if check_version and file_version != tor_version:
-            msg = "wrong version, tor is %s but the file's from %s" % (tor_version, file_version)
-            raise IOError(msg)
-        else:
-          raise IOError('unable to parse version')
+            if check_version and file_version != tor_version:
+              msg = "wrong version, tor is %s but the file's from %s" % (tor_version, file_version)
+              raise IOError(msg)
+          else:
+            raise IOError('unable to parse version')
 
-        while input_file_contents:
-          # gets category enum, failing if it doesn't exist
-          category = input_file_contents.pop(0).rstrip()
+          while input_file_contents:
+            # gets category enum, failing if it doesn't exist
+            category = input_file_contents.pop(0).rstrip()
 
-          if category not in Category:
-            base_msg = "invalid category in input file: '%s'"
-            raise IOError(base_msg % category)
+            if category not in Category:
+              base_msg = "invalid category in input file: '%s'"
+              raise IOError(base_msg % category)
 
-          # gets the position in the man page
-          index_arg, index_str = -1, input_file_contents.pop(0).rstrip()
+            # gets the position in the man page
+            index_arg, index_str = -1, input_file_contents.pop(0).rstrip()
 
-          if index_str.startswith('index: '):
-            index_str = index_str[7:]
+            if index_str.startswith('index: '):
+              index_str = index_str[7:]
 
-            if index_str.isdigit():
-              index_arg = int(index_str)
+              if index_str.isdigit():
+                index_arg = int(index_str)
+              else:
+                raise IOError('non-numeric index value: %s' % index_str)
             else:
-              raise IOError('non-numeric index value: %s' % index_str)
-          else:
-            raise IOError('malformed index argument: %s' % index_str)
-
-          option = input_file_contents.pop(0).rstrip()
-          argument = input_file_contents.pop(0).rstrip()
+              raise IOError('malformed index argument: %s' % index_str)
 
-          description, loaded_line = '', input_file_contents.pop(0)
+            option = input_file_contents.pop(0).rstrip()
+            argument = input_file_contents.pop(0).rstrip()
 
-          while loaded_line != PERSIST_ENTRY_DIVIDER:
-            description += loaded_line
+            description, loaded_line = '', input_file_contents.pop(0)
 
-            if input_file_contents:
-              loaded_line = input_file_contents.pop(0)
-            else:
-              break
-
-          CONFIG_DESCRIPTIONS[option.lower()] = ManPageEntry(option, index_arg, category, argument, description.rstrip())
-      except IndexError:
-        CONFIG_DESCRIPTIONS.clear()
-        raise IOError('input file format is invalid')
-    else:
-      man_call_results = system.call('man tor', None)
+            while loaded_line != PERSIST_ENTRY_DIVIDER:
+              description += loaded_line
 
-      if not man_call_results:
-        raise IOError('man page not found')
+              if input_file_contents:
+                loaded_line = input_file_contents.pop(0)
+              else:
+                break
 
-      # Fetches all options available with this tor instance. This isn't
-      # vital, and the valid_options are left empty if the call fails.
+            CONFIG_DESCRIPTIONS[option.lower()] = ManPageEntry(option, index_arg, category, argument, description.rstrip())
+        except IndexError:
+          CONFIG_DESCRIPTIONS.clear()
+          raise IOError('input file format is invalid')
+      else:
+        man_call_results = system.call('man tor', None)
 
-      controller, valid_options = tor_controller(), []
-      config_option_query = controller.get_info('config/names', None)
+        if not man_call_results:
+          raise IOError('man page not found')
 
-      if config_option_query:
-        for line in config_option_query.strip().split('\n'):
-          valid_options.append(line[:line.find(' ')].lower())
+        # Fetches all options available with this tor instance. This isn't
+        # vital, and the valid_options are left empty if the call fails.
 
-      option_count, last_option, last_arg = 0, None, None
-      last_category, last_description = Category.GENERAL, ''
+        controller, valid_options = tor_controller(), []
+        config_option_query = controller.get_info('config/names', None)
 
-      for line in man_call_results:
-        line = codecs.latin_1_encode(line, 'replace')[0]
-        line = ui_tools.get_printable(line)
-        stripped_line = line.strip()
+        if config_option_query:
+          for line in config_option_query.strip().split('\n'):
+            valid_options.append(line[:line.find(' ')].lower())
 
-        # we have content, but an indent less than an option (ignore line)
-        # if stripped_line and not line.startswith(' ' * MAN_OPT_INDENT): continue
+        option_count, last_option, last_arg = 0, None, None
+        last_category, last_description = Category.GENERAL, ''
 
-        # line starts with an indent equivilant to a new config option
+        for line in man_call_results:
+          line = codecs.latin_1_encode(line, 'replace')[0]
+          line = ui_tools.get_printable(line)
+          stripped_line = line.strip()
 
-        is_opt_indent = line.startswith(' ' * MAN_OPT_INDENT) and line[MAN_OPT_INDENT] != ' '
+          # we have content, but an indent less than an option (ignore line)
+          # if stripped_line and not line.startswith(' ' * MAN_OPT_INDENT): continue
 
-        is_category_line = not line.startswith(' ') and 'OPTIONS' in line
+          # line starts with an indent equivilant to a new config option
 
-        # if this is a category header or a new option, add an entry using the
-        # buffered results
+          is_opt_indent = line.startswith(' ' * MAN_OPT_INDENT) and line[MAN_OPT_INDENT] != ' '
 
-        if is_opt_indent or is_category_line:
-          # Filters the line based on if the option is recognized by tor or
-          # not. This isn't necessary for nyx, so if unable to make the check
-          # then we skip filtering (no loss, the map will just have some extra
-          # noise).
+          is_category_line = not line.startswith(' ') and 'OPTIONS' in line
 
-          stripped_description = last_description.strip()
+          # if this is a category header or a new option, add an entry using the
+          # buffered results
 
-          if last_option and (not valid_options or last_option.lower() in valid_options):
-            CONFIG_DESCRIPTIONS[last_option.lower()] = ManPageEntry(last_option, option_count, last_category, last_arg, stripped_description)
-            option_count += 1
+          if is_opt_indent or is_category_line:
+            # Filters the line based on if the option is recognized by tor or
+            # not. This isn't necessary for nyx, so if unable to make the check
+            # then we skip filtering (no loss, the map will just have some extra
+            # noise).
 
-          last_description = ''
+            stripped_description = last_description.strip()
 
-          # parses the option and argument
+            if last_option and (not valid_options or last_option.lower() in valid_options):
+              CONFIG_DESCRIPTIONS[last_option.lower()] = ManPageEntry(last_option, option_count, last_category, last_arg, stripped_description)
+              option_count += 1
 
-          line = line.strip()
-          div_index = line.find(' ')
+            last_description = ''
 
-          if div_index != -1:
-            last_option, last_arg = line[:div_index], line[div_index + 1:]
+            # parses the option and argument
 
-          # if this is a category header then switch it
+            line = line.strip()
+            div_index = line.find(' ')
 
-          if is_category_line:
-            if line.startswith('OPTIONS'):
-              last_category = Category.GENERAL
-            elif line.startswith('CLIENT'):
-              last_category = Category.CLIENT
-            elif line.startswith('SERVER'):
-              last_category = Category.RELAY
-            elif line.startswith('DIRECTORY SERVER'):
-              last_category = Category.DIRECTORY
-            elif line.startswith('DIRECTORY AUTHORITY SERVER'):
-              last_category = Category.AUTHORITY
-            elif line.startswith('HIDDEN SERVICE'):
-              last_category = Category.HIDDEN_SERVICE
-            elif line.startswith('TESTING NETWORK'):
-              last_category = Category.TESTING
-            else:
-              log.notice('Unrecognized category in the man page: %s' % line.strip())
-        else:
-          # Appends the text to the running description. Empty lines and lines
-          # starting with a specific indentation are used for formatting, for
-          # instance the ExitPolicy and TestingTorNetwork entries.
+            if div_index != -1:
+              last_option, last_arg = line[:div_index], line[div_index + 1:]
 
-          if last_description and last_description[-1] != '\n':
-            last_description += ' '
+            # if this is a category header then switch it
 
-          if not stripped_line:
-            last_description += '\n\n'
-          elif line.startswith(' ' * MAN_EX_INDENT):
-            last_description += '    %s\n' % stripped_line
+            if is_category_line:
+              if line.startswith('OPTIONS'):
+                last_category = Category.GENERAL
+              elif line.startswith('CLIENT'):
+                last_category = Category.CLIENT
+              elif line.startswith('SERVER'):
+                last_category = Category.RELAY
+              elif line.startswith('DIRECTORY SERVER'):
+                last_category = Category.DIRECTORY
+              elif line.startswith('DIRECTORY AUTHORITY SERVER'):
+                last_category = Category.AUTHORITY
+              elif line.startswith('HIDDEN SERVICE'):
+                last_category = Category.HIDDEN_SERVICE
+              elif line.startswith('TESTING NETWORK'):
+                last_category = Category.TESTING
+              else:
+                log.notice('Unrecognized category in the man page: %s' % line.strip())
           else:
-            last_description += stripped_line
-  except IOError as exc:
-    raised_exc = exc
+            # Appends the text to the running description. Empty lines and lines
+            # starting with a specific indentation are used for formatting, for
+            # instance the ExitPolicy and TestingTorNetwork entries.
 
-  CONFIG_DESCRIPTIONS_LOCK.release()
+            if last_description and last_description[-1] != '\n':
+              last_description += ' '
+
+            if not stripped_line:
+              last_description += '\n\n'
+            elif line.startswith(' ' * MAN_EX_INDENT):
+              last_description += '    %s\n' % stripped_line
+            else:
+              last_description += stripped_line
+    except IOError as exc:
+      raised_exc = exc
 
   if raised_exc:
     raise raised_exc
@@ -338,22 +336,21 @@ def save_option_descriptions(path):
 
   output_file = open(path, 'w')
 
-  CONFIG_DESCRIPTIONS_LOCK.acquire()
-  sorted_options = CONFIG_DESCRIPTIONS.keys()
-  sorted_options.sort()
+  with CONFIG_DESCRIPTIONS_LOCK:
+    sorted_options = CONFIG_DESCRIPTIONS.keys()
+    sorted_options.sort()
 
-  tor_version = tor_controller().get_info('version', '')
-  output_file.write('Tor Version %s\n' % tor_version)
+    tor_version = tor_controller().get_info('version', '')
+    output_file.write('Tor Version %s\n' % tor_version)
 
-  for i in range(len(sorted_options)):
-    man_entry = get_config_description(sorted_options[i])
-    output_file.write('%s\nindex: %i\n%s\n%s\n%s\n' % (man_entry.category, man_entry.index, man_entry.option, man_entry.arg_usage, man_entry.description))
+    for i in range(len(sorted_options)):
+      man_entry = get_config_description(sorted_options[i])
+      output_file.write('%s\nindex: %i\n%s\n%s\n%s\n' % (man_entry.category, man_entry.index, man_entry.option, man_entry.arg_usage, man_entry.description))
 
-    if i != len(sorted_options) - 1:
-      output_file.write(PERSIST_ENTRY_DIVIDER)
+      if i != len(sorted_options) - 1:
+        output_file.write(PERSIST_ENTRY_DIVIDER)
 
-  output_file.close()
-  CONFIG_DESCRIPTIONS_LOCK.release()
+    output_file.close()
 
 
 def get_config_summary(option):
@@ -391,15 +388,11 @@ def get_config_description(option):
     option - tor config option
   """
 
-  CONFIG_DESCRIPTIONS_LOCK.acquire()
-
-  if option.lower() in CONFIG_DESCRIPTIONS:
-    return_val = CONFIG_DESCRIPTIONS[option.lower()]
-  else:
-    return_val = None
-
-  CONFIG_DESCRIPTIONS_LOCK.release()
-  return return_val
+  with CONFIG_DESCRIPTIONS_LOCK:
+    if option.lower() in CONFIG_DESCRIPTIONS:
+      return CONFIG_DESCRIPTIONS[option.lower()]
+    else:
+      return None
 
 
 def get_config_options():
@@ -408,12 +401,8 @@ def get_config_options():
   list if no man page has been loaded.
   """
 
-  CONFIG_DESCRIPTIONS_LOCK.acquire()
-
-  return_val = [CONFIG_DESCRIPTIONS[opt].option for opt in CONFIG_DESCRIPTIONS]
-
-  CONFIG_DESCRIPTIONS_LOCK.release()
-  return return_val
+  with CONFIG_DESCRIPTIONS_LOCK:
+    return [CONFIG_DESCRIPTIONS[opt].option for opt in CONFIG_DESCRIPTIONS]
 
 
 def get_config_location():
@@ -853,28 +842,25 @@ class Torrc():
                    warning for this before then logs a warning
     """
 
-    self.vals_lock.acquire()
-
-    # clears contents and caches
-    self.contents, self.config_location = None, None
-    self.displayable_contents = None
-    self.stripped_contents = None
-    self.corrections = None
+    with self.vals_lock:
+      # clears contents and caches
+      self.contents, self.config_location = None, None
+      self.displayable_contents = None
+      self.stripped_contents = None
+      self.corrections = None
 
-    try:
-      self.config_location = get_config_location()
-      config_file = open(self.config_location, 'r')
-      self.contents = config_file.readlines()
-      config_file.close()
-    except IOError as exc:
-      if log_failure and not self.is_foad_fail_warned:
-        log.warn('Unable to load torrc (%s)' % exc.strerror)
-        self.is_foad_fail_warned = True
-
-      self.vals_lock.release()
-      raise exc
+      try:
+        self.config_location = get_config_location()
+        config_file = open(self.config_location, 'r')
+        self.contents = config_file.readlines()
+        config_file.close()
+      except IOError as exc:
+        if log_failure and not self.is_foad_fail_warned:
+          log.warn('Unable to load torrc (%s)' % exc.strerror)
+          self.is_foad_fail_warned = True
 
-    self.vals_lock.release()
+        self.vals_lock.release()
+        raise exc
 
   def is_loaded(self):
     """
@@ -896,10 +882,8 @@ class Torrc():
     Provides the contents of the configuration file.
     """
 
-    self.vals_lock.acquire()
-    return_val = list(self.contents) if self.contents else None
-    self.vals_lock.release()
-    return return_val
+    with self.vals_lock:
+      return list(self.contents) if self.contents else None
 
   def get_display_contents(self, strip = False):
     """
@@ -914,31 +898,27 @@ class Torrc():
       strip - removes comments and extra whitespace if true
     """
 
-    self.vals_lock.acquire()
-
-    if not self.is_loaded():
-      return_val = None
-    else:
-      if self.displayable_contents is None:
-        # restricts contents to displayable characters
-        self.displayable_contents = []
-
-        for line_number in range(len(self.contents)):
-          line_text = self.contents[line_number]
-          line_text = line_text.replace('\t', '   ')
-          line_text = ui_tools.get_printable(line_text)
-          self.displayable_contents.append(line_text)
+    with self.vals_lock:
+      if not self.is_loaded():
+        return None
+      else:
+        if self.displayable_contents is None:
+          # restricts contents to displayable characters
+          self.displayable_contents = []
 
-      if strip:
-        if self.stripped_contents is None:
-          self.stripped_contents = _strip_comments(self.displayable_contents)
+          for line_number in range(len(self.contents)):
+            line_text = self.contents[line_number]
+            line_text = line_text.replace('\t', '   ')
+            line_text = ui_tools.get_printable(line_text)
+            self.displayable_contents.append(line_text)
 
-        return_val = list(self.stripped_contents)
-      else:
-        return_val = list(self.displayable_contents)
+        if strip:
+          if self.stripped_contents is None:
+            self.stripped_contents = _strip_comments(self.displayable_contents)
 
-    self.vals_lock.release()
-    return return_val
+          return list(self.stripped_contents)
+        else:
+          return list(self.displayable_contents)
 
   def get_corrections(self):
     """
@@ -947,26 +927,22 @@ class Torrc():
     results.
     """
 
-    self.vals_lock.acquire()
-
-    if not self.is_loaded():
-      return_val = None
-    else:
-      tor_version = tor_controller().get_version(None)
-      skip_validation = not CONFIG['features.torrc.validate']
-      skip_validation |= (tor_version is None or not tor_version >= stem.version.Requirement.GETINFO_CONFIG_TEXT)
-
-      if skip_validation:
-        log.info('Skipping torrc validation (requires tor 0.2.2.7-alpha)')
-        return_val = {}
+    with self.vals_lock:
+      if not self.is_loaded():
+        return None
       else:
-        if self.corrections is None:
-          self.corrections = validate(self.contents)
+        tor_version = tor_controller().get_version(None)
+        skip_validation = not CONFIG['features.torrc.validate']
+        skip_validation |= (tor_version is None or not tor_version >= stem.version.Requirement.GETINFO_CONFIG_TEXT)
 
-        return_val = list(self.corrections)
+        if skip_validation:
+          log.info('Skipping torrc validation (requires tor 0.2.2.7-alpha)')
+          return {}
+        else:
+          if self.corrections is None:
+            self.corrections = validate(self.contents)
 
-    self.vals_lock.release()
-    return return_val
+          return list(self.corrections)
 
   def get_lock(self):
     """





More information about the tor-commits mailing list