changeset 45:c3802b8ed541

fixed the deadlock which occurred when adding multiple listeners during the open() call of the PulseAudioMixer
author Omair Majid <omajid@redhat.com>
date Wed, 06 Aug 2008 14:55:15 -0400
parents 4a01f1203d48
children 2331da2e5f6a
files .hgignore src/org/classpath/icedtea/pulseaudio/EventLoop.java src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java
diffstat 3 files changed, 64 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Wed Aug 06 14:55:15 2008 -0400
@@ -0,0 +1,8 @@
+# use glob syntax.
+syntax: glob
+
+*.class
+*.o
+*~
+org_classpath_icedtea_*.h
+*.log
--- a/src/org/classpath/icedtea/pulseaudio/EventLoop.java	Wed Aug 06 14:08:52 2008 -0400
+++ b/src/org/classpath/icedtea/pulseaudio/EventLoop.java	Wed Aug 06 14:55:15 2008 -0400
@@ -45,8 +45,8 @@
 import org.classpath.icedtea.pulseaudio.ContextEvent.Type;
 
 /*
- * any methods that can obstruct the behaviour of pa_mainloop
- * should run synchronized
+ * any methods that can obstruct the behaviour of pa_mainloop should run
+ * synchronized
  * 
  * 
  */
@@ -68,7 +68,7 @@
 	private String serverString;
 
 	private int status;
-	//	private boolean eventLoopIsRunning = false;
+	// private boolean eventLoopIsRunning = false;
 
 	public Semaphore finished = new Semaphore(0);
 
@@ -214,25 +214,16 @@
 	private void fireEvent(final ContextEvent e) {
 		System.out.println(this.getClass().getName() + "firing event: "
 				+ e.getType().toString());
-		Thread th = new Thread(new Runnable() {
+		System.out.println("notifying listeners");
 
-			@Override
-			public void run() {
-				System.out.println("notifying listeners");
-				
-				synchronized (contextListeners) {
-					System.out.println(contextListeners.size());
-					for (ContextListener listener : contextListeners) {
-						listener.update(e);
-						System.out.println("updating listeners");
-					}
-				}
+		synchronized (contextListeners) {
+			System.out.println(contextListeners.size());
+			for (ContextListener listener : contextListeners) {
+				listener.update(e);
+				System.out.println("updating listeners");
 			}
-
-		});
+		}
 
-		th.start();
-		
 	}
 
 	public void setVolume(long streamPointer, int volume) {
--- a/src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java	Wed Aug 06 14:08:52 2008 -0400
+++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java	Wed Aug 06 14:55:15 2008 -0400
@@ -308,12 +308,38 @@
 		eventLoop.setAppName(appName);
 		eventLoop.setServer(host);
 
+		
+		ContextListener eventListener = new ContextListener() {
+
+			@Override
+			public void update(ContextEvent e) {
+				System.out.println("General listener was notified");
+				System.out.println("  eventType: " + e.getType());
+				if (e.getType() == ContextEvent.Type.READY) {
+					System.out.println("firing event ready..");
+					fireEvent(new LineEvent(PulseAudioMixer.this,
+							LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED));
+					System.out.println("done");
+				} else if (e.getType() == ContextEvent.Type.FAILED
+						|| e.getType() == ContextEvent.Type.TERMINATED) {
+					fireEvent(new LineEvent(PulseAudioMixer.this,
+							LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED));
+				}
+				System.out.println("general listener returning");
+			}
+
+		};
+
+		eventLoop.addContextListener(eventListener);
+		
+		
 		final Semaphore ready = new Semaphore(0);
 
 		ContextListener initListener = new ContextListener() {
 
 			@Override
 			public void update(ContextEvent e) {
+				System.out.println("specific listener notifed");
 				System.out.println(this.getClass().getName()
 						+ ": Event detected " + e.getType().toString());
 				if (e.getType() == ContextEvent.Type.READY
@@ -322,6 +348,7 @@
 					ready.release();
 					System.out.println("realeasing semaphore ready");
 				}
+				System.out.println("specific listener returning");
 			}
 
 		};
@@ -355,48 +382,36 @@
 		}
 
 		System.out.println(this.getClass().getName() + ": ready");
-		
+
 		this.isOpen = true;
 
-//		ContextListener eventListener = new ContextListener() {
-//
-//			@Override
-//			public void update(ContextEvent e) {
-//				if (e.getType() == ContextEvent.Type.READY) {
-//
-//					fireEvent(new LineEvent(PulseAudioMixer.this,
-//							LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED));
-//				} else if (e.getType() == ContextEvent.Type.FAILED
-//						|| e.getType() == ContextEvent.Type.TERMINATED) {
-//					fireEvent(new LineEvent(PulseAudioMixer.this,
-//							LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED));
-//				}
-//
-//			}
-//
-//		};
 
-//		eventLoop.addContextListener(eventListener);
 
 	}
 
 	@Override
-	synchronized public void removeLineListener(LineListener listener) {
+	public void removeLineListener(LineListener listener) {
 		lineListeners.remove(listener);
 	}
 
-	synchronized private void fireEvent(final LineEvent e) {
-		Thread th = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				synchronized (lineListeners) {
-					for (LineListener lineListener : lineListeners) {
-						lineListener.update(e);
-					}
-				}
+	/*
+	 * Should this method be synchronized? I had a few reasons, but i forgot them
+	 * Pros:
+	 *  - Thread safety?
+	 * 
+	 * Cons:
+	 *  - eventListeners are run from other threads, if those then call fireEvent 
+	 *    while a method is waiting on a listener, this synchronized block wont 
+	 *    be entered: deadlock!
+	 * 
+	 */
+	private void fireEvent(final LineEvent e) {
+		System.out.println(this.getClass().getName() + "fireEvent(): firing event");
+		synchronized (lineListeners) {
+			for (LineListener lineListener : lineListeners) {
+				lineListener.update(e);
 			}
-		});
-		th.start();
+		}
 	}
 
 	public static void main(String[] args) throws Exception {