From: Radu B. R. <ru...@cs...> - 2007-02-04 20:09:18
|
Geoffrey Biggs wrote: > - Dynamic arrays cannot be in embedded structures contained within a > message. For example, if you have an array of structures as part of the > message, those structures cannot contain dynamically allocated arrays. > This is because of the way memory allocation is handled for unpacking > received messages. The xdr filter function called for the embedded > structure type doesn't know if it's encoding or decoding, and so doesn't > know if it needs to allocate memory or not. I'm not sure how to get > around this problem yet. Would this be possible if additional information were specified in the message? Or, what about changing the packing function by generating two signatures: one for XDR_ENCODE and one for XDR_DECODE ? Not sure how or if this would work though yet. > - When an array is encoded with XDR, it seems to encode the pointer into > the message as well, even though this is rather useless. It results in 4 > extra bytes being sent. I'm not sure why this is happening, perhaps > someone more familiar with XDR knows. I remember running into this last year while building Javaclient2. I searched the archives and found Brian's explanation: http://www.nabble.com/player2-thoughts-tf1123613.html#a2939874. > A. When a message goes from client to driver: > 1 - Client allocates local copy (handled by client writer). > 2 - Client deletes local copy (because client is single-threaded for > writing to server, no conflict with needing to wait till message gets > packed). > 3 - Unpacking function on server allocates (handled automatically). > 4 - Somewhere on the server, once message has been handled, array needs > to be deleted (handled by driver writer?). [...] > A.4 shouldn't be too bad, but it's not that nice for drivers to have to > free memory allocated elsewhere once they've handled a message. I would solve A.4 by building some driverbase classes (the same way we have imagebase now for example) and make the actual drivers inherit from it/them, or, put additional constraints on the way the driver code should look. The latter would be also useful for easier future modifications of a driver by someone else as well as for keeping a certain structure in place. Note that right now different drivers look very different, implementation-wise, from each other. This is ok for 3rd party drivers which are not in the repository, but for those included in the Player distro, it makes things a bit tougher to manage over time. (One trivial example where I saw something like this useful was to have different debug levels for each driver in particular - different than the ones for the server - which range from some simple messages like "port open", "port closed" to higher levels like actually displaying the packages/bytes being sent over the wire to the hardware device on screen). > B. When a message goes from driver to client: > 1 - Driver allocates local copy (handled by driver writer) > 2 - Memory allocated by driver needs to be deleted after message is > packed. Due to threading, message may not be packed as soon as Publish > is called, so cannot delete after Publish returns (memory leak!). > 3 - Unpacking function on client allocates (handled automatically). > 4 - Client library deletes after handling message, or passes ownership > on via returning to client program (handled either by client lib dev or > client program dev). > > The problematic ones are the deletes: > > B.4 could be problematic if other transport layers are introduces which > handle dynamic arrays better and so don't need the client library to > delete manually. > > B.2 is the worst. Because of threading issues, the driver can't free the > memory itself without risking a race condition, nor can it reuse that > memory. The playertcp can't free it because it doesn't know how to (a > message body is opaque to it, and, as far as it knows, static). What > should probably happen here is that when Publish is called a deep copy > of the message structure is made instead of a shallow copy (which works > fine so far because we haven't had dynamically allocated memory to worry > about), but because the inside of messages isn't known, this is difficult. I think B.4 is not a big problem, because if a different transport mechanism will be implemented (by making use of ace, ice, corba, etc or similar), it usually have its own packing structures, so I think we wouldn't end up using XDR for it anyway. Somebody please correct me if I'm wrong. I agree with B.2, and at first glance, I also see deep copying as the immediate solution. How much overhead would that add though? > One possible way to manage all this deleting is created a > FinishMessage() function or similar that, when called, will clean up a > message after it's been used (either packed or handled). This function > will need to know how to clean up each message, so a customised function > for each message is necessary. However, rather than writing these, we > could automatically generate them similar to the packing functions, and > use a function table to look them up in FinishMessage() and call the > appropriate one. Messages without any dynamically allocated memory would > have an empty function, and if we inlined these they would disappear > (optimising compilers should remove empty functions anyway). The > function table lookup could be considered wasteful, though, when the > bulk of messages don't need cleaning up. Auto-generation could also be > used to create functions to handle deep copies of messages made when > they get pushed onto message queues. This sounds cool. What are the drawbacks ? I didn't understand the last part where you said that "when the bulk of messages don't need cleaning up". Anyway, very very cool analysis Geoff! I hope others will join the discussion so we can move towards a ready-to-implement phase. Cheers, Radu. -- | Radu Bogdan Rusu | http://rbrusu.com/ | http://www9.cs.tum.edu/people/rusu/ | Intelligent Autonomous Systems | Technische Universitaet Muenchen |