Hi Marcel, lol! Guess I was asking for that... please rest assure that I am aware of how Java works thanks you ;) Let me just reply to the relevant part..
> Because that would not solve the problem. The design choices are not OSGi's, > they are Java's. We write Java, so the least we must do is learn the > language. Concurrency is an important aspect of the language, and > understanding the Java memory model is crucial. This is where I disagree. It is an OSGi design choices to use for example a synchronous service lifecycle event mechanism. This single choice, and I am not even saying it is bad per se, will probably be responsible for 99 out of 100 deadlocks in an OSGi environment (excluding the framework itself ;). Not just because people don't understand the details of concurrency or are being lazy, but because this design choice makes this aspect hard to handle for the programmer. My feeling is that an asynchronous model would be more forgiving, robust and scalable. I also think, looking at the specs, that OSGi has been struggling with these choices. Some thing synchronous, some thing asynchronous and sometimes you can choose. Most explicit is maybe the spec requirements that ConfigurationAdmin must invoke updated() asynchronous so that people can synchronize for initialization(104.5.5). Think about that for a minute... requiring a compendium service to behave as a async consumer while any arbitrary consumer can invoke the producer sync at that point (because that how java works). Now along that train of thought I was thinking we can't change OSGI, but again this choice is in the dependency manager. You must have though about sync/async behavior on the add and it would be trivial to make it async. So that is where my whys came in... why did OSGi choose this sync model, why did you choose it for dm.add as well and why should I not consider making it async. > Of course you can argue that OSGi should have used a model similar to Java > EE, disallowing bundles to take advantage of threads and concurrency, but > that would have seriously limited the usefulness of OSGi. Now you are being dramatic.. but in essence yeah. I think the any framework should make a trade off between usefulness and usability :D grz Bram On Sat, Dec 17, 2011 at 10:51 PM, Marcel Offermans <[email protected]> wrote: > Hello Bram, > > On Dec 17, 2011, at 18:52 PM, Bram de Kruijff wrote: of >> 2011/12/16 Marcel Offermans <[email protected]>: >>> With the risk of sounding like a school teacher (which I'm trying to >>> avoid)... >> >> Haha.. I don't mind some education so don't hold back on my account :) >> >>> Up to here we're fine. We are invoking the dependency manager, but only >>> declaring a component without actually handing it to the manager is fine. >>> >>> m_dependencyManager.add(component); >> >> Ok, clear and just found this is actually documented in the spec under 4.7.3 >> >> {quote} >> 4.7.3 Synchronization Pitfalls >> Generally, a bundle that calls a listener should not hold any Java monitors. >> This means that neither the Framework nor the originator of a synchronous >> event should be in a monitor when a callback is initiated. >> The purpose of a Java monitor is to protect the update of data structures. >> This should be a small region of code that does not call any code the effect >> of >> which cannot be overseen. Calling the OSGi Framework from synchronized >> code can cause unexpected side effects. One of these side effects might be >> deadlock. A deadlock is the situation where two threads are blocked because >> they are waiting for each other. >> Time-outs can be used to break deadlocks, but Java monitors do not have >> time-outs. Therefore, the code will hang forever until the system is reset >> (Java has deprecated all methods that can stop a thread). This type of >> deadlock >> is prevented by not calling the Framework (or other code that might >> cause callbacks) in a synchronized block. >> If locks are necessary when calling other code, use the Java monitor to >> create >> semaphores that can time-out and thus provide an opportunity to escape a >> deadlocked situation. >> {quote} > >> Now this is all fine, but as you are in teacher mode... *scary voice >> of Igor* why!? > > The generic answer is that you simply cannot hold any locks if you invoke a > method on some instance that might call you back (on another thread). Locks > should be held for as short a period of time as possible anyway, so invoking > methods while holding a lock is something you should review every time it > happens. This has nothing to do with the OSGi framework. > > Let me show you an example of how this can go wrong (you might want to > copy/paste this to your IDE): > > public class MyClass { > public static void main(String[] args) { > // let's start by simulating a framework > Framework fw = new Framework(); > // now we create some kind of component that > // interacts with the framework > Caller c = new Caller(fw); > // and we start that component > c.start(); > } > > public static class Caller { > private Framework m_fw; > > public Caller(Framework fw) { > // as soon as the component initializes, it also > // simulates registering as a service with the > // framework > m_fw = fw; > m_fw.register(this); > } > > public synchronized void start() { > // the last line of the main method was to invoke > // start, so here we do something naughty, like > // invoking some method on the framework while > // holding a lock (this method is synchronized) > m_fw.doSomething(); > } > > public synchronized void go() { > // eventually, the framework wants to invoke this > // method, and it is also synchronized > System.out.println("Go go go!"); > } > } > > public static class Framework { > private Caller m_service; > > public void doSomething() { > Thread t = new Thread() { > public void run() { > System.out.println("Invoking service"); > // this is where the deadlock occurs, this > // new thread now tries to invoke a different > // method on our component, but because > // doSomething was invoked while holding a > // lock in the other thread, and the other > // thread is now waiting (in its join() method) > // until this one's done, we deadlock > m_service.go(); > System.out.println("DEADLOCKED: we never get to this point"); > }; > }; > try { > // let's assume that the framework launches a thread > // that does some work and waits for this work to complete > t.start(); > t.join(); > } > catch (InterruptedException e) { > e.printStackTrace(); > } > } > > public void register(Caller service) { > m_service = service; > } > } > } > > This demonstrates a deadlock caused by holding a lock. The comments should > explain what's going on. Now this is just an example, I've seen way more > complex call graphs and loops occur in real life code that eventually caused > deadlocks. The example also shows that this has nothing to do with OSGi > itself. > >> It always feels awkward to have a dynamic services architecture and >> then when thinking about interface semantics having to be aware and >> concerned with how the framework and consumers handle threads when it >> comes to side effects. > > Basically, OSGi inherits all features from Java itself. Java is a multi > threaded language. When designing a class, unless you are 100% sure that it > can never be called by more than one thread at a time, you always need to > take thread safety into account. Granted, most people are not exposed to Java > nowadays, they are exposed to writing Java EE, and there your code runs in a > container that manages threads for you (you're not supposed to make them > yourself, nor are you supposed to make your code thread safe). > >> I can only guess about OSGi design choices and >> am afraid something like "resource constraint devices' is in the >> answers, but obviously something like sync life-cycle events is a >> recipe for deadlocks. So, without trying to redesign OSGi, for >> example... Why don't we have an async add(Component)? > > Because that would not solve the problem. The design choices are not OSGi's, > they are Java's. We write Java, so the least we must do is learn the > language. Concurrency is an important aspect of the language, and > understanding the Java memory model is crucial. > > Of course you can argue that OSGi should have used a model similar to Java > EE, disallowing bundles to take advantage of threads and concurrency, but > that would have seriously limited the usefulness of OSGi. > > Greetings, Marcel > > > _______________________________________________ > Amdatu-developers mailing list > [email protected] > http://lists.amdatu.org/mailman/listinfo/amdatu-developers _______________________________________________ Amdatu-developers mailing list [email protected] http://lists.amdatu.org/mailman/listinfo/amdatu-developers

