Am 18.08.2010 01:12, schrieb Clemens Zeidler:
Am 18.08.2010, 10:20 Uhr, schrieb Stephan Assmus <superstippi@xxxxxx>:Am 18.08.2010 00:08, schrieb Stephan Assmus:For all calls that get called by ServerWindow threads, the locking needs to work by using the multi-locker. Basically the data accessed via the Desktop class, and the data accessed via the ServerWindow class can run in one of three threads: The desktop thread, the app thread, or the window thread. The window threads are the performance critical ones, and they should run concurrently. So whenever something is supposed to run in a ServerWindow thread only, the read-lock is used from within the ServerWindow threads themselves. For all other cases, the write lock is used, which makes sure that no two ServerWindow threads, or ServerApp threads, or the Desktop thread itself access the same (Desktop owned) data concurrently. All that being said, I have the impression since you tried the multi-lock define, and since you added the new message code to the _MessageNeedsAllWindowsLocked() method, you've had a pretty good idea about this already, I just wanted to recap a little. :-)...and yet I am still not happy with the description. Forgot to mention that this only works, since the code in the Desktop and ServerApp classes *always* write-lock. If that code would sometimes read-lock only, it would potentially access the same data that a ServerWindow thread accesses concurrently. Any data that a ServerWindow thread accesses with only the read-lock held needs to be completely private and separate from all other ServerWindows. Sometimes it's tricky not to introduce deadlocks this way, and I've considered using the same global MultiLock instance for *every* locking requirement of the app_server code. Yet there are a few objects with their own BLocker or even MultiLock, like the globally shared cursor, various managers like the FontManager, the FontCache backend, and so on. Most stuff is heavily tested and ok (short protected "inner" sections of code), but some stuff I am not so sure about, for example the separate HWInterface MultiLock and how concurrent access to the same accelerant add-on is handled. At the moment no acceleration is used at all, but perhaps the locking needs to be redesigned for it to work properly at all. It's unfortunately not the freshest thing in my memory either... :-) Best regards, -StephanThank you, nice overview! had a rough overview but that makes it even clearer. I just read locked it now *) I hope I got it right? Regards, Clemens ps. To access the returned Window you have to hold a lock anyway because otherwise the Window could have gone in the meantime. *) Window* Desktop::WindowForClientLooperPort(port_id port) { AutoReadLocker locker(fWindowLock); for (Window* window = fAllWindows.FirstWindow(); window != NULL; window = window->NextWindow(kAllWindowList)) { if (window->ServerWindow()->ClientLooperPort() == port) return window; } return NULL; }
Since the window list does not change, a read-lock appears appropriate. However, the code is (probably) broken now, since MultiLocker does not support nested read-locking. If you remove the message code from the list that requires write-locking in ServerWindow, then the code is definitely broken. MultiLocker supports nested write-locks, I don't know what happens when the current write-lock-owner acquires a read-lock. The (read-lock) assert that Axel mentions may indeed be the best solution.
Best regards, -Stephan