# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import threading

from devil.utils import reraiser_thread
from devil.utils import timeout_retry


class WeakConstant(object):
  """A thread-safe, lazily initialized object.

  This does not support modification after initialization. The intended
  constant nature of the object is not enforced, though, hence the "weak".
  """

  def __init__(self, initializer):
    self._initialized = threading.Event()
    self._initializer = initializer
    self._lock = threading.Lock()
    self._val = None

  def read(self):
    """Get the object, creating it if necessary."""
    if self._initialized.is_set():
      return self._val
    with self._lock:
      if not self._initialized.is_set():
        # We initialize the value on a separate thread to protect
        # from holding self._lock indefinitely in the event that
        # self._initializer hangs.
        initializer_thread = reraiser_thread.ReraiserThread(self._initializer)
        initializer_thread.start()
        timeout_retry.WaitFor(
            lambda: initializer_thread.join(1) or not initializer_thread.
            isAlive(),
            wait_period=0)
        self._val = initializer_thread.GetReturnValue()
        self._initialized.set()

    return self._val
