<commit_before>/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.util

import java.util.concurrent.locks.{ Condition, Lock, ReadWriteLock, ReentrantReadWriteLock }

trait Cached[T] {
  private val rwLock = new ReentrantReadWriteLock
  private val ready = rwLock.writeLock.newCondition
  private var inProgress = false
  private var elem : Option[T] = None
  
  def apply[U](op : T => U) : U = {
    val rl = rwLock.readLock
    val wl = rwLock.writeLock
    
    locked(rl) {
      elem match {
        case Some(t) => return op(t)
        case _ =>
      }
    }
    
    wl.lock
    while (!elem.isDefined) {
      try {
        while (inProgress)
          ready.await
      } catch {
        case ex : InterruptedException =>
          if (!elem.isDefined) {
            wl.unlock
            throw ex
          }
      }
        
      if (!elem.isDefined) {
        inProgress = true
        wl.unlock
	      try {
          val t = create
          wl.lock
          elem = Some(t)
        } finally {
          locked(wl) {
            inProgress = false
            ready.signalAll
          }
        }
      }
    }
    
    locked(rl) {
      wl.unlock
      op(elem.get)
    }
  }
  
  def invalidate() {
    val oldElem =
      locked(rwLock.writeLock) {
        val elem0 = elem
        elem = None
        elem0
      }
    
    oldElem match {
      case Some(t) => destroy(t)
      case _ =>
    }
  }

  protected def create() : T

  protected def destroy(t : T)
  
  private def locked[U](l : Lock)(op : => U) : U = {
    try {
      l.lock
      op
    } finally {
      l.unlock
    }
  }
}
<commit_msg>Deadlock. Waiting on a write lock condition is a bad idea. Fix by simplification<commit_after>/*
 * Copyright 2005-2010 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.util

trait Cached[T] {
  private var inProgress = false
  private var elem : Option[T] = None
  
  def apply[U](op : T => U) : U = {
    val e = synchronized {
      elem match {
        case Some(t) => t
        case None => {
          while (!elem.isDefined) {
            try {
              while (inProgress)
                wait
            } catch {
              case ex : InterruptedException =>
                if (!elem.isDefined) {
                  throw ex
                }
            }
        
            if (!elem.isDefined) {
              inProgress = true
              try {
                val t = create
                elem = Some(t)
              } finally {
                inProgress = false
                notifyAll
              }
            }
          }
          elem.get
	}
      }
    }
    
    op(e)
  }
  
  def invalidate() {
    val oldElem = synchronized {
      val elem0 = elem
      elem = None
      elem0
    }
    
    oldElem match {
      case Some(t) => destroy(t)
      case _ =>
    }
  }

  protected def create() : T

  protected def destroy(t : T)
}

{'fraction_non_alphanumeric': 0.09815950920245399, 'fraction_numerical': 0.006816632583503749, 'mean_word_length': 1.2751937984496124, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3834453', 'n_tokens_mistral': 937, 'n_tokens_neox': 906, 'n_words': 225}