User: simone  
  Date: 00/12/12 01:56:06

  Added:       src/main/org/jboss/util Semaphore.java
  Log:
  Semaphore implementation: allows only N clients to access critical sections of code.
  
  Revision  Changes    Path
  1.1                  jboss/src/main/org/jboss/util/Semaphore.java
  
  Index: Semaphore.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.util;
  
  import java.util.Iterator;
  import java.util.Map;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.io.StringWriter;
  import java.io.PrintWriter;
  
  /**
   * Semaphore that can allow a specified number of threads to enter, blocking the
   * others. If the specified number of threads is 1, it acts as an exclusive semaphore
   * and can be used instead of synchronized blocks
   *
   * @author Simone Bordet ([EMAIL PROTECTED])
   * @version $Revision: 1.1 $
   */
  public class Semaphore 
        implements Sync
  {
        // Constants -----------------------------------------------------
  
        // Attributes ----------------------------------------------------
        private boolean m_debug;
        private int m_users;
        private Map m_logMap;
  
        // Static --------------------------------------------------------
  
        // Constructors --------------------------------------------------
        public Semaphore(int users)
        {
                if (users < 1) throw new IllegalArgumentException();
                m_users = users;
                m_logMap = new HashMap();
                m_debug = false;
        }
  
        // Public --------------------------------------------------------
  
        // Sync implementation ----------------------------------------------
        public void acquire() throws InterruptedException
        {
                synchronized (this)
                {
                        logAcquire();
                        
                        while (m_users <= 0)
                        {
                                // Wait (forever) until notified. To discover 
deadlocks,
                                // turn on debugging of this class
                                long start = System.currentTimeMillis();
                                wait(30000);
                                long end = System.currentTimeMillis();
  
                                if ((end - start) > 29000)
                                {
                                        logDeadlock();
                                }
                        }
                        --m_users;
                }
        }
        public boolean attempt(long msecs) throws InterruptedException
        {
                // TODO...
                return false;
        }
        public void release()
        {
                synchronized (this)
                {
                        logRelease();
                        
                        ++m_users;
                        notify();
                }
        }
  
        // Object overrides ---------------------------------------------------
        public String toString()
        {
                return super.toString() + " - " + m_users;
        }
  
        // Package protected ---------------------------------------------
  
        // Protected -----------------------------------------------------
        protected void logAcquire()
        {
                if (m_debug) 
                {
                        // Check if thread is already mapped
                        Thread thread = Thread.currentThread();
  
                        // Create stack trace
                        StringWriter sw = new StringWriter();
                        new Exception().printStackTrace(new PrintWriter(sw));
                        String trace = sw.toString();
                
                        LinkedList list = (LinkedList)m_logMap.get(thread);
                        if (list != null)
                        {
                                // Thread is mapped
                                // Add info
                                Info prevInfo = (Info)list.getLast();
                                Info info = new Info(thread, m_users, trace);
                                list.add(info);
                        }
                        else
                        {
                                // Thread is not mapped, create list and add counter
                                list = new LinkedList();
                                Info info = new Info(thread, m_users, trace);
                                list.add(info);
                                // Map thread
                                m_logMap.put(thread, list);
                        }
                }
        }
        protected void logDeadlock()
        {
                System.err.println();
                System.err.println("DEADLOCK ON SEMAPHORE " + this);
                if (m_debug)
                {
                        for (Iterator i = m_logMap.values().iterator(); i.hasNext();) 
                        {
                                LinkedList list = (LinkedList)i.next();
                                for (Iterator iter = list.iterator(); iter.hasNext();)
                                {
                                        System.err.println(iter.next());
                                }
                        }
                }
                System.err.println();
        }
        protected void logRelease()
        {
                if (m_debug)
                {
                        // Find a matching thread and remove info for it
                        Thread thread = Thread.currentThread();
  
                        LinkedList list = (LinkedList)m_logMap.get(thread);
                        if (list != null) 
                        {
                                Info info = new Info(thread, 0, "");
                                if (!list.remove(info))
                                {
                                        System.err.println("LOG INFO SIZE: " + list);
                                        new IllegalStateException("BUG: semaphore log 
list does not contain required info").printStackTrace();
                                }
  
                                // If no info left, remove the mapping
                                int size = list.size();
                                if (size < 1) 
                                {
                                        m_logMap.remove(thread);
                                }
                        }                       
                        else 
                        {
                                throw new IllegalStateException("Semaphore log failed: 
release called without acquire");
                        }
                }
        }
  
        // Private -------------------------------------------------------
  
        // Inner classes -------------------------------------------------
        private class Info
        {
                private Info(Thread t, int i, String s)
                {
                        m_thread = t;
                        m_counter = i;
                        m_trace = s;
                }
                private Thread m_thread;
                private int m_counter;
                private String m_trace;
                public boolean equals(Object o) 
                {
                        Info other = (Info)o;
                        return m_thread == other.m_thread;
                }
                public String toString() 
                {
                        return m_thread + " - " + m_counter + "\n" + m_trace;
                }
        }
  }
  
  
  

Reply via email to