GCC suport for Objective-C [Was: NSSound Reimplementation]
David Chisnall schrieb: On 16 Jul 2009, at 18:34, Riccardo Mottola wrote: Sorry, I just haven't had a chance to look at installing a new/different compiler and working with that yet, though it really IS something I'd like to be playing with. However, it doesn't really have any bearing on this issue because we have to develop code for the existing compiler and will need to do so as long as we continue to support it (gcc). Yes, I remember a caveat: that was it, no gcc support. As a GNU project I'd be quite waey to drop gcc support. As a GNU project, I'd hope that the GNU compiler collection would put some effort into supporting us! Someone at Apple sent them patches for supporting declared properties over a year ago, and yet GCC still does not support any of the extensions added in OS X 10.5, which was released two years ago. Snow Leopard is going to make heavy use of blocks and declared properties in the API, and if we want to remain compatible, we are going to need a compiler that supports these. It would be really great if GCC would, but I have yet to see any evidence that anyone is still actively working on Objective-C support in GCC. In the last two years, Clang has gone from having no Objective-C support to supporting most of Objective-C 2 on the GNU runtime, while GCC has not gained a single new Objective-C feature. David, your mail got me thinking, I wont switch to Clang and I don't hope GNUstep as a project will. So the only option forward is to start working on better Objective-C support in gcc. I surely wont have time for this beside my maintainer task on GNUstep, but this seems currently the more important task. I will have a look at the code in gcc that supports Objective-C and if I am able to make any sense of it, I might switch over to work on that. Cheers Fred ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: GCC suport for Objective-C [Was: NSSound Reimplementation]
Hi Fred, On 18 Jul 2009, at 19:23, Fred Kiefer wrote: your mail got me thinking, I wont switch to Clang and I don't hope GNUstep as a project will. So the only option forward is to start working on better Objective-C support in gcc. I surely wont have time for this beside my maintainer task on GNUstep, but this seems currently the more important task. I will have a look at the code in gcc that supports Objective-C and if I am able to make any sense of it, I might switch over to work on that. That would be great. It's not a task for the faint hearted though. You can find all of the GCC Objective-C code in this file: http://gcc.gnu.org/viewcvs/trunk/gcc/objc/objc-act.c?revision=149722view=markup There seem to be two functions in this file related to ivar access / assignment, so it ought to be relatively easy for anyone familiar with GCC internals to add non-fragile ivar support. You also need to modify the ivar structure initialiser to contain negative values for the offsets (this is the hint I give to the runtime to indicate that this compilation unit provides support for non-fragile ivars and needs the offsets updated accordingly). David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On Thu, Jul 16, 2009 at 10:37 AM, David Chisnallthera...@sucs.org wrote: On 16 Jul 2009, at 14:23, Jamie Ramone wrote: I'd like to chime in here and say that this approach IS actually a good idea as : 1 ) it does solve the ABI change breakdown problem and Except that it doesn't, it just hides it. Now people subclassing and referencing variables in the superclass need to explicitly cast a pointer to a structure. If this structure changes, they need to manually update their private copy of the ivars and if they don't thing break in exciting ways. 2 ) it is actually much easier to read because it's a prime example of encapsulation and abstraction, so complexity is hidden. It is not easier to read, because now you need a separate structure definition, every ivar access has to go via a macro which will look something like this: #define ivar (((struct private_ivars*)_private)-ivar) In no possible way is that clearer code. So locality of reference is gone. It gets replaced by messaging an object. OK. So what? Why depend on locality? Again, I'm hard pressed to find an objective way to choose one over the other. If the API of the messaged object is well defined then I find both forms of the code to be equally understandable. But that's my opinion, some may agree and others disagree. So this reasoning is also a bad one for judging the approach. Clearly you have no idea what locality of reference means. See here: http://en.wikipedia.org/wiki/Locality_of_reference In summary, for good performance you want data that is accessed together to be close together in memory. Both CPUs (via their cache architecture) and operating systems (via their paging strategy) optimise heavily for this case. Having ivars dangled off on a separate structure means that we now need two cache lines per object instead of one. Actually, it's worse if you also factor in subclasses doing this because you need one cache line for the object and one for each of the subclass structures. This will increase cache churn considerably. This is very difficult to identify in a microbenchmark, but it affect performance in larger programs quite noticeably. These structures, being separately allocated and of different sizes, may well be on different pages meaning that you will end up with a lot of more swapping when you are low on memory, which completely cripples performance. The correct solution is to declare no ivars other than ones you are willing to commit to maintaining in the future in the header, declare them all in the implementation file, and use non-fragile ivar support in the runtime, but this requires people to actually test my patch which adds this. At the very least, we should just add an unused pointer for future expansion so that we can add new ivars later and not use this for ivars that are likely to remain stable for several releases. David I see where you were going, sorry for the mix-up. I do understand what locality means, I just thought you were talking about scope. My bad, just an honest mistake so don't have a cow man :-P Now, if the compiler optimized in such a way that small enough ivars are packed together as one single piece of data, and the needed one is accessed once loaded into a register then there would be a locality problem by separating them. If not, the cache use increases by one piece of data: the pointer to the object. The individual fields would be accessed separately anyway in this case, whether whitin the object or in two separate ones. So there is an increase it is only limited to the ammount of different classes using the approach. You say there's a problem if subclasses do the same, but that wouldn't happen. The separate object for containing the ivars would only be in the public classes of the library in question. There's no reason for a programmer who makes use of that library to do so in any subclass, except maby in those subclasses that are part of some other api API and it's implementation is based on the former. Now, one could optimize it by moving ivars up the hierarchy. But if the superclasses are also public the ABI would break, and on the other ones (non-public ones) the risk of having potentialy usless ivars, thus increasing memory usage. If the separate-object is used as proposed (not with the non-optimization previously pointed out), the object's creation could be delayed until one of those ivar's are needed i.e. a lazy approach. This way the memory usage is minimal, as far as this aproach allows. That macro puzzles me. Why would you have a macro to access and ivar that way? Because if the code is a method then it is accessed as if it were a global variable. If not then you should use an accessor method. Trying to access them directly punches a hole in the OOP paradigm. If you have to, then maybe you shouldn't use an OOP approach at all, but rather wrap procedural code with an object layer. Oh, one more thing, could you post a
Re: NSSound Reimplementation
The discussion seems to have settled a little, so I'll go ahead and ask the question... what approach should I be taking here? I really do not have the know-how to chime in, and because of that will go with whatever is decided. What Richard did with NSOperations seems easy enough, is that the direction we're going with? I'm hearing a lot of stuff but nothing seems to be definite/written in stone. David: It's not that I don't want to try llvm/clang out, it's just that I don't have time! Start in September I'll have even less time (starting grad school). I'm trying my best to get this code out so I can at least have 1 - 1.5 months of bug hunting until I will be forced into a maintenance mode. I'd really like to be able to try a lot of this stuff out, but I just can't, sorry. Thanks Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 28 Jun 2009, at 19:14, Stefan Bidigaray wrote: As promised, here's the latest code. Feel free to poke as many holes in it as possible. I'm going to use this, almost completely unchanged, for NSSound.m. The bundle/plug-in stuff will go in 100% unchanged. Sorry that I just haven't found time to look at this. But ... going back to the issue of avoiding changes to ivars breaking ABI in future releases ... the approach I currently favor is having a *single* ivar in the public class. This is a private id variable referring to an instance of a private class which is used to hold the real ivars. So the implementation file contains this private class (whose ivars are all declared public so that any code in the implementation file can access them freely), and the -init and -dealloc methods of the public class create/destroy an instance of the private class. Look at the code for NSOperation.m in the current svn trunk version of the base library for the simplest example around. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 09:30, Richard Frith-Macdonald wrote: But ... going back to the issue of avoiding changes to ivars breaking ABI in future releases ... the approach I currently favor is having a *single* ivar in the public class. This is a private id variable referring to an instance of a private class which is used to hold the real ivars. I really don't like this approach. It makes the code difficult to read, destroys locality of reference, and hurts performance. Please, please, please, can other people test my non-fragile ivars patch so that we can get rid of ugly hacks like this and just not declare any ivars in the headers. I posted it months ago and have had absolutely no reports of testing yet. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
I'd like to chime in here and say that this approach IS actually a good idea as : 1 ) it does solve the ABI change breakdown problem and 2 ) it is actually much easier to read because it's a prime example of encapsulation and abstraction, so complexity is hidden. The use here of encapsulation and abstraction are precisely (among other reasons) why the object oriented paradigm exists. Leveraging these concepts allow one to concentrate on a specific problem by hiding away the details of the rest behind an API, that of the other objects you're using from within whichever one you're working on. If the code is hard to read then that api is not well defined, so the real problem would be to redefine it so as to make it understandable (read: actually usable). Depending on being able to see all (or most) of the details at once is not a good idea. Another thing I might add is that readability is something rather subjective (though there are generalities like statistics to allow it to be an objective measurement), so it shouldn't be used to choose or dismiss a program writing method. So locality of reference is gone. It gets replaced by messaging an object. OK. So what? Why depend on locality? Again, I'm hard pressed to find an objective way to choose one over the other. If the API of the messaged object is well defined then I find both forms of the code to be equally understandable. But that's my opinion, some may agree and others disagree. So this reasoning is also a bad one for judging the approach. The performance hurting one I like. This is something that CAN actually be measured, so it's perfect for considering this approach. Now, why exactly does it hurt performance? Is the amount lost so much greater than the amount achieved by the overall algorithm used that it performs slower than if that algorithm wasn't used? How fast does the code need to be, minimally? These are the questions one should ask (and answer) in order to move ahead here. So I agree with Richard here. However, if no one else changes the code and you do, and submit a patch as you did, and it does solve the problems you're looking to solve, then I don't see why your patch wouldn't be accepted. -- Besos, abrazos, confeti y aplausos. Jamie Ramone El Vikingo ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 14:23, Jamie Ramone wrote: I'd like to chime in here and say that this approach IS actually a good idea as : 1 ) it does solve the ABI change breakdown problem and Except that it doesn't, it just hides it. Now people subclassing and referencing variables in the superclass need to explicitly cast a pointer to a structure. If this structure changes, they need to manually update their private copy of the ivars and if they don't thing break in exciting ways. 2 ) it is actually much easier to read because it's a prime example of encapsulation and abstraction, so complexity is hidden. It is not easier to read, because now you need a separate structure definition, every ivar access has to go via a macro which will look something like this: #define ivar (((struct private_ivars*)_private)-ivar) In no possible way is that clearer code. So locality of reference is gone. It gets replaced by messaging an object. OK. So what? Why depend on locality? Again, I'm hard pressed to find an objective way to choose one over the other. If the API of the messaged object is well defined then I find both forms of the code to be equally understandable. But that's my opinion, some may agree and others disagree. So this reasoning is also a bad one for judging the approach. Clearly you have no idea what locality of reference means. See here: http://en.wikipedia.org/wiki/Locality_of_reference In summary, for good performance you want data that is accessed together to be close together in memory. Both CPUs (via their cache architecture) and operating systems (via their paging strategy) optimise heavily for this case. Having ivars dangled off on a separate structure means that we now need two cache lines per object instead of one. Actually, it's worse if you also factor in subclasses doing this because you need one cache line for the object and one for each of the subclass structures. This will increase cache churn considerably. This is very difficult to identify in a microbenchmark, but it affect performance in larger programs quite noticeably. These structures, being separately allocated and of different sizes, may well be on different pages meaning that you will end up with a lot of more swapping when you are low on memory, which completely cripples performance. The correct solution is to declare no ivars other than ones you are willing to commit to maintaining in the future in the header, declare them all in the implementation file, and use non-fragile ivar support in the runtime, but this requires people to actually test my patch which adds this. At the very least, we should just add an unused pointer for future expansion so that we can add new ivars later and not use this for ivars that are likely to remain stable for several releases. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 11:24, David Chisnall wrote: On 16 Jul 2009, at 09:30, Richard Frith-Macdonald wrote: But ... going back to the issue of avoiding changes to ivars breaking ABI in future releases ... the approach I currently favor is having a *single* ivar in the public class. This is a private id variable referring to an instance of a private class which is used to hold the real ivars. I really don't like this approach. It makes the code difficult to read, destroys locality of reference, and hurts performance. Please, please, please, can other people test my non-fragile ivars patch so that we can get rid of ugly hacks like this and just not declare any ivars in the headers. I posted it months ago and have had absolutely no reports of testing yet. Sorry, I just haven't had a chance to look at installing a new/ different compiler and working with that yet, though it really IS something I'd like to be playing with. However, it doesn't really have any bearing on this issue because we have to develop code for the existing compiler and will need to do so as long as we continue to support it (gcc). I honestly can't see gcc being dropped any time soon (in the first place we would want all GNUstep to have been working flawlessly with clang for a good long time... perhaps a year) before we could reasonably think of making Clang the preferred compiler, let alone deprecating or removing support for gcc, and in the second place there may be political considerations preventing it (though I think most of the core developers are less likely to be bothered about that than in many free software projects ). I think we have to live within the limitations of gcc as long as we haven't deprecated it. The nice thing about this particular scheme (a single instance variable in the public class pointing to another class containing the actual variables) is that it's clean and simple enough to make it *very* easy to change if/when we change compilers at a later date. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 14:37, David Chisnall wrote: On 16 Jul 2009, at 14:23, Jamie Ramone wrote: I'd like to chime in here and say that this approach IS actually a good idea as : 1 ) it does solve the ABI change breakdown problem and Except that it doesn't, it just hides it. Now people subclassing and referencing variables in the superclass need to explicitly cast a pointer to a structure. If this structure changes, they need to manually update their private copy of the ivars and if they don't thing break in exciting ways. No ... people subclassing NEVER reference any variables of the superclass, because the superclass only contains a single instance variable, and that's declared @private. Because the superclass only ever contains the single instance variable, it never changes with impementation details, and the ABI doesn't change. 2 ) it is actually much easier to read because it's a prime example of encapsulation and abstraction, so complexity is hidden. It is not easier to read, because now you need a separate structure definition, every ivar access has to go via a macro which will look something like this: #define ivar (((struct private_ivars*)_private)-ivar) Actually it's #define private ((PrivateClass*)_private) Then private-ivar = ... Which can easily be converted to 'self-ivar' or just 'ivar' by a global replace when we want to change because we have non-fragile ivars available. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Am 16.07.2009 um 12:24 schrieb David Chisnall: On 16 Jul 2009, at 09:30, Richard Frith-Macdonald wrote: But ... going back to the issue of avoiding changes to ivars breaking ABI in future releases ... the approach I currently favor is having a *single* ivar in the public class. This is a private id variable referring to an instance of a private class which is used to hold the real ivars. I really don't like this approach. It makes the code difficult to read, destroys locality of reference, and hurts performance. Please, please, please, can other people test my non-fragile ivars patch so that we can get rid of ugly hacks like this and just not declare any ivars in the headers. I posted it months ago and have had absolutely no reports of testing yet. Maybe it's not clear to everybody what benefits your patch introduces. So maybe it would be a good idea to give a short enumeration of all the gains to the broader public (I know you're good at writing technical articles since I read quite a few off them :-)). David thanks, Lars ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 14:53, Richard Frith-Macdonald wrote: On 16 Jul 2009, at 14:37, David Chisnall wrote: On 16 Jul 2009, at 14:23, Jamie Ramone wrote: I'd like to chime in here and say that this approach IS actually a good idea as : 1 ) it does solve the ABI change breakdown problem and Except that it doesn't, it just hides it. Now people subclassing and referencing variables in the superclass need to explicitly cast a pointer to a structure. If this structure changes, they need to manually update their private copy of the ivars and if they don't thing break in exciting ways. No ... people subclassing NEVER reference any variables of the superclass, because the superclass only contains a single instance variable, and that's declared @private. Because the superclass only ever contains the single instance variable, it never changes with impementation details, and the ABI doesn't change. 2 ) it is actually much easier to read because it's a prime example of encapsulation and abstraction, so complexity is hidden. It is not easier to read, because now you need a separate structure definition, every ivar access has to go via a macro which will look something like this: #define ivar (((struct private_ivars*)_private)-ivar) Actually it's #define private ((PrivateClass*)_private) Then private-ivar = ... Which can easily be converted to 'self-ivar' or just 'ivar' by a global replace when we want to change because we have non-fragile ivars available. Thinking about it, this is actually very short/easy to do with the preprocessor to support both gcc and clang (though I think we'd need to comment it well) ... eg. #if clang #define private self @interface MyClass { #else #define private ((MyClassPrivate*)_private) @interface MyClassPrivate : NSObject { @public #endif // instance variables here } @end #if !clang @implementation MyClassPrivate @end #endif @implementation MyClass - (id) init { #if !clang _private = [MyPrivateClass new]; #endif // ivar initialisation here return self; } ... @end So if we are building with clang then we use non-fragile ivars, but if we are building with gcc then we use the private class instance to store our ivars. To make it even simpler when using the same model repeatedly, we could use macros and end up writing code like this: GSBEGINPRIVATEIVARS(MyClass) int var1; charvar2; GSENDPRIVATEIVARS(MyClass) @implementation MyClass - (id) init { GSCREATEPRIVATEIVARS(MyClass) ... return self; } ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 17:41, Richard Frith-Macdonald wrote: On 16 Jul 2009, at 14:53, Richard Frith-Macdonald wrote: On 16 Jul 2009, at 14:37, David Chisnall wrote: On 16 Jul 2009, at 14:23, Jamie Ramone wrote: I'd like to chime in here and say that this approach IS actually a good idea as : 1 ) it does solve the ABI change breakdown problem and Except that it doesn't, it just hides it. Now people subclassing and referencing variables in the superclass need to explicitly cast a pointer to a structure. If this structure changes, they need to manually update their private copy of the ivars and if they don't thing break in exciting ways. No ... people subclassing NEVER reference any variables of the superclass, because the superclass only contains a single instance variable, and that's declared @private. Because the superclass only ever contains the single instance variable, it never changes with impementation details, and the ABI doesn't change. 2 ) it is actually much easier to read because it's a prime example of encapsulation and abstraction, so complexity is hidden. It is not easier to read, because now you need a separate structure definition, every ivar access has to go via a macro which will look something like this: #define ivar (((struct private_ivars*)_private)-ivar) Actually it's #define private ((PrivateClass*)_private) Then private-ivar = ... Which can easily be converted to 'self-ivar' or just 'ivar' by a global replace when we want to change because we have non-fragile ivars available. Thinking about it, this is actually very short/easy to do with the preprocessor to support both gcc and clang (though I think we'd need to comment it well) ... eg. #if clang #define private self @interface MyClass { #else #define private ((MyClassPrivate*)_private) @interface MyClassPrivate : NSObject { @public #endif // instance variables here } @end #if !clang @implementation MyClassPrivate @end #endif @implementation MyClass - (id) init { #if !clang _private = [MyPrivateClass new]; #endif // ivar initialisation here return self; } ... @end So if we are building with clang then we use non-fragile ivars, but if we are building with gcc then we use the private class instance to store our ivars. To make it even simpler when using the same model repeatedly, we could use macros and end up writing code like this: GSBEGINPRIVATEIVARS(MyClass) int var1; charvar2; GSENDPRIVATEIVARS(MyClass) @implementation MyClass - (id) init { GSCREATEPRIVATEIVARS(MyClass) ... return self; } Looks sensible. Is anyone interested in adding non-fragile ABI support to GCC? The initial implementation is in clang because GCC code hurts my brain, but I'd like to see both compilers support this. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 17:26, Lars Sonchocky-Helldorf wrote: Maybe it's not clear to everybody what benefits your patch introduces. So maybe it would be a good idea to give a short enumeration of all the gains to the broader public (I know you're good at writing technical articles since I read quite a few off them :-)). As I wrote in my first email, it provides the same benefits as Apple's non-fragile ABI: You can add or re-arrange instance variables in a class without breaking the ABI. You can also remove private instance variables. Instance variable offsets are now stored in a global variable, rather than being hard-coded, and are set when the class is loaded by the runtime. This needs a small amount of compiler and runtime support. The runtime support was in the diff I sent to this list, the compiler support is in clang (and hopefully someone will add equivalent support to GCC). Unlike the Apple implementation, it does not require the superclass to be compiled with the non-fragile ABI, so you can still compile GNUstep with the old ABI and then create subclasses of GNUstep classes compiled with the non-fragile ABI. If you rearrange or add ivars in a GNUstep class, then the subclass will still work correctly, as long as it was compiled with -fnonfragile-abi. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Hey, But ... going back to the issue of avoiding changes to ivars breaking ABI in future releases ... the approach I currently favor is having a *single* ivar in the public class. This is a private id variable referring to an instance of a private class which is used to hold the real ivars. I really don't like this approach. It makes the code difficult to read, destroys locality of reference, and hurts performance. I don't like it either! I think it was discussed quite a bit and we did not agree that it was the way to go! The discussion didn't come to a conclusion (I remember we also discussed it at FOSDEM), but many agreed that this opaque single-ivar solution was bad. I personally would prefer just breaking the ABI if other solutions are a too big effort. Second place of course is David's. I cannot remember now why i didn't try it though... did your patch have some prerequisites? Riccardo ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Hi, At the very least, we should just add an unused pointer for future expansion so that we can add new ivars later and not use this for ivars that are likely to remain stable for several releases. Agreed. --R ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Hi, Sorry, I just haven't had a chance to look at installing a new/different compiler and working with that yet, though it really IS something I'd like to be playing with. However, it doesn't really have any bearing on this issue because we have to develop code for the existing compiler and will need to do so as long as we continue to support it (gcc). Yes, I remember a caveat: that was it, no gcc support. As a GNU project I'd be quite waey to drop gcc support. As for testing the patch, clang is not available as a package in gentoo, thus I was too lazy to install it in another way. This also marks the diffusion of clang up to now though. Riccardo ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 18:00, David Chisnall wrote: On 16 Jul 2009, at 17:26, Lars Sonchocky-Helldorf wrote: Maybe it's not clear to everybody what benefits your patch introduces. So maybe it would be a good idea to give a short enumeration of all the gains to the broader public (I know you're good at writing technical articles since I read quite a few off them :-)). As I wrote in my first email, it provides the same benefits as Apple's non-fragile ABI: You can add or re-arrange instance variables in a class without breaking the ABI. You can also remove private instance variables. Instance variable offsets are now stored in a global variable, rather than being hard-coded, and are set when the class is loaded by the runtime. This needs a small amount of compiler and runtime support. The runtime support was in the diff I sent to this list, the compiler support is in clang (and hopefully someone will add equivalent support to GCC). Unlike the Apple implementation, it does not require the superclass to be compiled with the non-fragile ABI, so you can still compile GNUstep with the old ABI and then create subclasses of GNUstep classes compiled with the non-fragile ABI. If you rearrange or add ivars in a GNUstep class, then the subclass will still work correctly, as long as it was compiled with -fnonfragile-abi. One thing I don't understand about the whole issue of adding ivars is how it is supposed to work with key value coding since, in KVC you can get/set the value of an ivar by name, but with non-fragile ivars you can presumably have multiple ivars with the same name. What does KVC do in that situation? ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 18:59, Richard Frith-Macdonald wrote: One thing I don't understand about the whole issue of adding ivars is how it is supposed to work with key value coding since, in KVC you can get/set the value of an ivar by name, but with non-fragile ivars you can presumably have multiple ivars with the same name. What does KVC do in that situation? Break, probably. It will find the first ivar with that name, which will be the one in the subclass. You can, of course, avoid this problem by creating explicit accessors which KVC will find in preference to direct ivar access. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 16 Jul 2009, at 18:34, Riccardo Mottola wrote: Hi, Sorry, I just haven't had a chance to look at installing a new/ different compiler and working with that yet, though it really IS something I'd like to be playing with. However, it doesn't really have any bearing on this issue because we have to develop code for the existing compiler and will need to do so as long as we continue to support it (gcc). Yes, I remember a caveat: that was it, no gcc support. As a GNU project I'd be quite waey to drop gcc support. As a GNU project, I'd hope that the GNU compiler collection would put some effort into supporting us! Someone at Apple sent them patches for supporting declared properties over a year ago, and yet GCC still does not support any of the extensions added in OS X 10.5, which was released two years ago. Snow Leopard is going to make heavy use of blocks and declared properties in the API, and if we want to remain compatible, we are going to need a compiler that supports these. It would be really great if GCC would, but I have yet to see any evidence that anyone is still actively working on Objective-C support in GCC. In the last two years, Clang has gone from having no Objective-C support to supporting most of Objective-C 2 on the GNU runtime, while GCC has not gained a single new Objective-C feature. As for testing the patch, clang is not available as a package in gentoo, thus I was too lazy to install it in another way. This also marks the diffusion of clang up to now though. Building clang from source is pretty trivial. It is the system compiler for FreeBSD 8 and is in packages for a number of Linux distributions and Free/OpenBSD. Not sure about Solaris. Clang 1.0 is being released with the next LLVM release (2.6, due in September). David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 30 Jun 2009, at 07:36, Wolfgang Lux wrote: There is a subtle difference between OS X and GNUstep: As far as I understand the code, threadInfo-inputFd is not even checked if the run loop has no event sources and no timer and it is just added implicitly to the event sources in -pollUntil:within: in GSRunLoopCtxt. On OS X, on the other hand, (the equivalent of) threadInfo-inputFd automatically becomes an input source once the thread starts a new thread. So, if you call NSRunLoop's - runMode:beforeDate: in GNUstep after starting a new thread without adding a timer or an input source, it returns immediately with NO and it does not perform an invocation scheduled by the secondary thread, whereas on OS X -runMode:beforeDate: performs the scheduled invocation and then returns YES. If I find time, I'll try to make up a test case. Yes please ... sounds like one of those cases where GNUstep does what the documentation says rather than what OSX actually does. It's always good to mirror the OSX behavior for compatibility (and note things in our documentation). We can probably mimic that behavior fairly easily. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 28 Jun 2009, at 21:46, Wolfgang Lux wrote: Stefan Bidigaray wrote: I tried setting waitUntilDone to YES, still no luck! The - _finished method still doesn't get called when calling - performSelectorOnMainThread:..., for now I've just made that a - performSelector:withObject:, which works, but is not what I want done. I guess my next question here is: is - performSelectorOnMainThread:withObject:waitUntilDone: working? Maybe I built -base incorrectly? I don't think so. The problem with - performSelectorOnMainThread:withObject:waitUntilDone: is that the call is only scheduled to be executed by the run loop of the main thread. Thus, the call will not be executed before the next event is received or the next timer expires on the main thread. Not exactly ... calling - performSelectorOnMainThread:withObject:waitUntilDone: also triggers an event in the run loop of the main thread (by writing to a pipe that the thread is listening to), so as the pipe will wake up a sleeping thread, the call should be executed pretty much immediately (though after any other work already in progress, or waiting to execute) as long as the loop is running. This is indeed different from Mac OS X, where the scheduled call seems to be executed immediately if the run loop is idle. OSX is supposed to behave the same way as GNUstep... it should handle the perform on the next run loop iteration, so if the loop is not being run the perform should be held up until it is. Maybe the runloop is not running, or maybe it's running, but not in the mode that was specified for the method to be performed in? ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On Mon, Jun 29, 2009 at 12:59 AM, Richard Frith-Macdonald rich...@tiptree.demon.co.uk wrote: Maybe the runloop is not running, or maybe it's running, but not in the mode that was specified for the method to be performed in? This would probably explain it! I don't have a run loop on that test... it's just a straight shot. I went back to the Apple doc on it, reread it and realized I completely missed the paragraph that said it queued the message on the run loop! Thanks Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
I had a look at the code you posted yesterday and I've found two dubious points in NSSound_test.m: and here is a third, minor point: In the -dealloc method of NSSound you check whether self is still an element of the dictionary nameDict. This is completely unnecessary since the dictionary retains its elements and therefore if a sound object is deallocated and the test self == [nameDict objectForKey:_name] succeeds this would mean that self has been incorrectly released too often. Wolfgang ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Thanks Wolfgang, this stuff really helps. On Sat, Jun 27, 2009 at 4:32 PM, Wolfgang Lux wolfgang@gmail.comwrote: I had a look at the code you posted yesterday and I've found two dubious points in NSSound_test.m: First, there is a retain/release error in NSSound's -initWithContentsOfFile:byRef: method. The NSData object returned from dataWithContentsOfMappedFile: is already autoreleased, but you release that object after calling -initWithData: (recall that you should only release objects that you own, which in general are only objects that you have allocated yourself either with alloc or copy). I went ahead and made this change. Is the reason I wasn't getting a seg fault due to the TEST_RELEASE instead of a normal RELEASE? Second, I noticed that you call -performSelectorOnMainThread... with waitUntilDone = NO. I think you should use waitUntilDone = YES here. Note that if waitUntilDone = NO and you call -performSelectorOnMainThread... from the main thread the call is scheduled to be run at the next iteration of the run loop and not performed immediately. In addition, if you really use waitUntilDone = NO on purpose you should make sure that the sound object is retained until the scheduled method is actually run (i.e., you probably should retain self before calling performSelectorOnMainThread and autorelease self in _finished). Otherwise, there is a chance that the thread which calls the _stream method releases the sound object too early and the run loop invokes _finished for an already released object. I tried setting waitUntilDone to YES, still no luck! The -_finished method still doesn't get called when calling -performSelectorOnMainThread:..., for now I've just made that a -performSelector:withObject:, which works, but is not what I want done. I guess my next question here is: is -performSelectorOnMainThread:withObject:waitUntilDone: working? Maybe I built -base incorrectly? As for the check in -dealloc, it was inherited from the original implementation, I'll go ahead and remove it. This probably explains why I used to get a crash whenever -dealloc was called. On related news I've implemented the bundle/plug-in loading code, and so far it works flawlessly. There's still a lot that needs to be done, but I think I might have this fully implemented by mid July. I'm also having issues with -setCurrentTime:, I'm now using sf_seek() in SndfileSource.m and the tool will crash either on that call or on sf_read_short() in -_stream. The best I've come up with is that sf_seek() and sf_read_short() are trying to access the same data, at the same time (sf_seek() is called from the main thread and sf_read_short() from the stream thread) and blowing up. I thought adding a lock in NSSound's -setCurrentTime: would fix this problem but it did not. Hopefully I'll get some more stuff done today and will post the latest version of the test tool for you guys to take a look. Thanks Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
As promised, here's the latest code. Feel free to poke as many holes in it as possible. I'm going to use this, almost completely unchanged, for NSSound.m. The bundle/plug-in stuff will go in 100% unchanged. To build this, you'll need to go into the bundles/ directory to build and install the 2 bundles/plug-ins before hand. The plug-ins are not required, the NSSound object will simply be destroyed (see -initWithData:) if suitable plug-ins are not found. There are a few FIXME tags in NSSound_test.m, these are there to remind me that I need to fix that before going any further (suggestions are welcome). The FIXME in -soundNamed: however, is not mine and I really do not know what to do there. Thanks Stefan nssoundtest.tar.gz Description: GNU Zip compressed data ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Stefan Bidigaray wrote: I tried setting waitUntilDone to YES, still no luck! The - _finished method still doesn't get called when calling - performSelectorOnMainThread:..., for now I've just made that a - performSelector:withObject:, which works, but is not what I want done. I guess my next question here is: is - performSelectorOnMainThread:withObject:waitUntilDone: working? Maybe I built -base incorrectly? I don't think so. The problem with - performSelectorOnMainThread:withObject:waitUntilDone: is that the call is only scheduled to be executed by the run loop of the main thread. Thus, the call will not be executed before the next event is received or the next timer expires on the main thread. This is indeed different from Mac OS X, where the scheduled call seems to be executed immediately if the run loop is idle. As a workaround, you could schedule a timer that regularly invokes an empty method in your NSSound class on the main thread, e.g., [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @selector(_heartBeat:) userInfo: nil repeats: YES]; and - (void)_heartBeat:(NSTimer *) { } Wolfgang ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
I know I'm replying a lot to my own posts, but that's just it's me. Anyway, I've been doing some more testing and the -performSelectorOnMainThread:withObject:waitUntilDone: call in -_stream is not really getting executed, as far as I can tell. I moved the DESTROY(lock) stuff into -_finished: and was getting a seg fault later down the line. I set a break point inside -_finished:, but gdb never got to it, which leads me to believe the method is not being called. I then replaced that call with -performSelector:withObject:, which the way understand simply does the same thing but on the secondary thread, and it worked. Is -performSelectorOnMainThread:... not working? Thanks Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Am 27.06.2009 um 18:06 schrieb Stefan Bidigaray: I know I'm replying a lot to my own posts, but that's just it's me. Anyway, I've been doing some more testing and the - performSelectorOnMainThread:withObject:waitUntilDone: call in - _stream is not really getting executed, as far as I can tell. I moved the DESTROY(lock) stuff into -_finished: and was getting a seg fault later down the line. I set a break point inside - _finished:, but gdb never got to it, which leads me to believe the method is not being called. I then replaced that call with - performSelector:withObject:, which the way understand simply does the same thing but on the secondary thread, and it worked. Is - performSelectorOnMainThread:... not working? I had a look at the code you posted yesterday and I've found two dubious points in NSSound_test.m: First, there is a retain/release error in NSSound's - initWithContentsOfFile:byRef: method. The NSData object returned from dataWithContentsOfMappedFile: is already autoreleased, but you release that object after calling -initWithData: (recall that you should only release objects that you own, which in general are only objects that you have allocated yourself either with alloc or copy). Second, I noticed that you call -performSelectorOnMainThread... with waitUntilDone = NO. I think you should use waitUntilDone = YES here. Note that if waitUntilDone = NO and you call - performSelectorOnMainThread... from the main thread the call is scheduled to be run at the next iteration of the run loop and not performed immediately. In addition, if you really use waitUntilDone = NO on purpose you should make sure that the sound object is retained until the scheduled method is actually run (i.e., you probably should retain self before calling performSelectorOnMainThread and autorelease self in _finished). Otherwise, there is a chance that the thread which calls the _stream method releases the sound object too early and the run loop invokes _finished for an already released object. Wolfgang ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
In case you guys didn't know, my weekends start of Fridays (4 day a week work schedule). I actually started testing last night and, to my suprise, it worked pretty well (I've attached my test tool). It would be really great to get some input on the code itself. It's missing quite a bit or functionality but the over all play, stop, etc stuff is working. Here's what I know isn't working: * -isPlaying is still kind of weird because I'm using the NSConditionLock's condition to figure out if it's playing but that doesn't get destroyed when the sound naturally reaches the end of the line (would appreciate some suggests on how to make sure this happens). * -stop destroys the NSConditionLock, but to make sure it doesn't before -_stream is done with it I put a sleep() there. This is related to the -isPlaying thing above... I'm think the best thing for me to do here is have -_stream destroy the lock, is that a good idea? * -currentTime and -setCurrentTime are screwy. I need to go back in SndfileSource.m and have those method use sndfile's tell and seek function. It's real funny watching .ogg and .flac files play and the output of -currentTime is 1/3 of the actual play time. * Like I mentioned before, still no bundle loading stuff! I'm just including SndfileSource.m and AudioOutputSink.m in the NSSound_test.m file... just a real quick and dirty workaround for now. I also have a question: how can I find out if I have any objects that are not getting deallocated? In case you didn't catch from my previous stuff I'm pretty bad a memory management. Thanks Stefan nssoundtest.tar.gz Description: GNU Zip compressed data ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 19 Jun 2009, at 08:05, Fred Kiefer wrote: Stefan Bidigaray wrote: It would really help if I attached the file... I don't understand the general concept here, so just a few detail comments on the code itself. Hiding the implementation details in the header is a good thing, but it makes the code in the implementation harder to read. This could be improved by using local variables (or even Macros). For example - (BOOL) pause { NSConditionLock *lock = (NSConditionLock*)_private[2]; if ([lock condition] == SOUND_SHOULD_PAUSE) { return NO; } if ([lock tryLock] == NO) { return NO; } [lock unlockWithCondition: SOUND_SHOULD_PAUSE]; return YES; } I would go further and ask what the point of the _private array is? By convention all the instance variables are private (that's what the leading underscore in the variable name means), so if all that's required is to inform developers that they should not use the ivars directly, there's no point in having the array, but maybe it would be worth using a @private declaration. On the other hand, if the idea is to hide the implementation details so that ivar layouts won't need to change with future revisions (something I think we should all be doing), my preference would be to have a single pointer to a structure containing the required data. eg. struct _NSSoundInternal; @interface NSSound : NSObject NSCoding, NSCopying { @private struct _NSSoundInternal *_internal; } Then the designated initialiser allocates memory for the structure, clears it, and assigns the pointer when an instance is initialised, and -dealloc frees the memory at the end, and all internal references to ivars just go indirect from that pointer. The implementation is completely hidden/private and can be changed in subsequent releases without breaking the ABI. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On Fri, Jun 19, 2009 at 2:05 AM, Fred Kiefer fredkie...@gmx.de wrote: I don't understand the general concept here, so just a few detail comments on the code itself. I'll try to explain this the best I can, it might be a little long, though... As I explained on my previous e-mails, I'm streaming the data to the sink. In order to do so without blocking the main thread I'm using a separate thread (spawned using -detachNewThreadSelector:toTarget:withObject:)... this will happen in -play and the selector is -_stream. The stream uses 2 objects, one conforms to GSSoundSource and the other to GSSoundSink, the former outputs the data in a standard format so that the latter can send it to the audio device. To pause and resume the stream I use an NSConditionLock, which is what _private[2] is, if the condition is SOUND_SHOULD_PAUSE the while loop waits until it's SOUND_SHOULD_PLAY. The hardest part, at least for me, is finding out if the thread is already running in -play and -stop and taking the appropiate action. The -pause and -resume methods are pretty straight forward. Hiding the implementation details in the header is a good thing, but it makes the code in the implementation harder to read. This could be improved by using local variables (or even Macros). For example Sounds good! When releasing the conditional lock, you should rather destroy it, as it could otherwise just be reused, although it has been freed. Wouldn't this cause a bit of a problem in -_stream since I keep checking the NSConditionLock's condition? My plan was to initialize it in -play and free/destroy it in -stop and use it as the way to find out if the audio data is being streamed. Shouldn't the condition of the while loop read something like this? while ((!_shouldExit) (bytesRead 0) success) Yes! Oops... I've attached a copy of GSSoundSource.h and GSSoundSink.h, these two header files define the protocols and give you an idea of what exactly I'm going for. I've also gone ahead and added documention as well. I'll also go ahead and attach the first two classes that implement these protocols. As before, I haven't had time to test them, so I'm sure there are typos everywhere. I do plan on testing them later today, make sure they actually do what they're supposed to before finishing the NSSound implentation. Thanks Stefan /* GSSoundSink.h Sink audio data. Copyright (C) 2009 Free Software Foundation, Inc. Written by: Stefan Bidigaray stefanb...@gmail.com Date: Jun 2009 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, see http://www.gnu.org/licenses/ or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _GNUstep_H_GSSoundSink #define _GNUstep_H_GSSoundSink @protocol GSSoundSink NSObject /** init/ * Initializes the receiver for output using the defined parameters. * pbWARNING:/b This method does not open the device, see -open./p */ - (id)initWithEncoding: (int)encoding channels: (NSUInteger)channelCount sampleRate: (NSUInteger)sampleRate byteOrder: (NSByteOrder)byteOrder; /** Opens the device for output, called by [NSSound-play]. */ - (BOOL)open; /** Closes the device, called by [NSSound-stop]. */ - (void)close; /** Writes/Plays the data in bytes to the device. Data imust/i be in * the same format as specified in * -initWithEncoding:channels:sampleRate:byteOrder:. */ - (BOOL)writeBytes: (void *)bytes length: (NSUInteger)length; /** Called by [NSSound-setVolume:], and corresponds to it. Parameter volume * is between the values 0.0 and 1.0. */ - (void)setVolume: (float)volume; /** Called by [NSSound-volume]. */ - (float)volume; /** Called by [NSSound-setPlaybackDeviceIdentifier:]. */ - (void)setPlaybackDeviceIdentifier: (NSString *)playbackDeviceIdentifier; /** Called by [NSSound-playbackDeviceIdentifier]. */ - (NSString *)playbackDeviceIdentifier; /** Called by [NSSound-setChannelMapping:]. */ - (void)setChannelMapping: (NSArray *)channelMapping; /** Called by [NSSound-channelMapping]. */ - (NSArray *)channelMapping; @end #endif // _GNUstep_H_GSSoundSink /* GSSoundSource.h Load and read sound data. Copyright (C) 2009 Free Software Foundation, Inc. Written by: Stefan Bidigaray stefanb...@gmail.com
Re: NSSound Reimplementation
On Fri, Jun 19, 2009 at 4:26 AM, Richard Frith-Macdonald rich...@tiptree.demon.co.uk wrote: I would go further and ask what the point of the _private array is? Well, the only reason I could come up with right now is that I didn't want to have to include GSSoundSink.h and GSSoundSource.h. The guy writing an application really doesn't care if these two protocols exist, so I figured it was best to hide the fact that I used them, and a NSCondtionLock, all together. That's why I put this out there before continuing, I wanted to make sure it was a good decision. By convention all the instance variables are private (that's what the leading underscore in the variable name means), so if all that's required is to inform developers that they should not use the ivars directly, there's no point in having the array, but maybe it would be worth using a @private declaration. On the other hand, if the idea is to hide the implementation details so that ivar layouts won't need to change with future revisions (something I think we should all be doing), my preference would be to have a single pointer to a structure containing the required data. eg. struct _NSSoundInternal; @interface NSSound : NSObject NSCoding, NSCopying { @private struct _NSSoundInternal *_internal; } Then the designated initialiser allocates memory for the structure, clears it, and assigns the pointer when an instance is initialised, and -dealloc frees the memory at the end, and all internal references to ivars just go indirect from that pointer. The implementation is completely hidden/private and can be changed in subsequent releases without breaking the ABI. Should I do this instead? Fact of the matter is, I'm not sure if the way I'm going about this is the best way forward, so chances are it'll eventually change (hence why I created an array of 4 (void *) but am only using 3 pointers). I would gladly go this route, specially since, like everyone else here, I'm all for ABI compatibility. Thanks Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
It would really help if I attached the file... @interface NSSound : NSObject NSCoding, NSCopying { NSString *_name; NSData *_data; NSString *_playbackDeviceIdentifier; // Currently unused NSArray *_channelMapping; // Currently unused BOOL _onlyReference; id _delegate; NSTimeInterval _duration; // Private info: // 0 - input bundle (idGSSoundSource) // 1 - output bundle (idGSSoundSink) // 2 - lock (NSConditionLock *) void *_private[4]; BOOL _shouldStop; } - (void)_stream { NSUInteger bytesRead; BOOL bytesWereWritten; BOOL success; void *bytes; bytes = NSZoneMalloc(NSDefaultMallocZone(), BUFFER_SIZE); bytesRead = [(idGSSoundSource)_private[0] readBytes: bytes length: BUFFER_SIZE]; while ((!_shouldExit) || (bytesRead 0) || (!success)) { /* FIXME */ if ([(NSConditionLock*)_private[2] condition] == SOUND_SHOULD_PAUSE) { [(NSConditionLock*)_private[2] lockWhenCondtion: SOUND_SHOULD_PLAY]; [(NSConditionLock*)_private[2] unlock]; } success = [(idGSSoundSink)_private[1] writeBytes: bytes length: bytesRead]; bytesRead = [(idGSSoundSource)_private[0] readBytes: bytes length: BUFFER_SIZE]; } [self performSelectorOnMainThread: @selector(_finished:) withObject: [NSNumber numberforBool: success] waitUntilDone: NO]; } - (BOOL) pause { if ([(NSConditionLock*)_private[2] condition] == SOUND_SHOULD_PAUSE) { return NO; } if ([(NSConditionLock*)_private[2] tryLock] == NO) { return NO; } [(NSConditionLock*)_private[2] unlockWithCondition: SOUND_SHOULD_PAUSE]; return YES; } - (BOOL) play { // If the NSCondtionLock exists it's because NSSound is either playing or paused if ((NSConditionLock*)_private[2] != nil) { return NO; } _private[2] = (void *)[NSCondtionLock initWithCondition: SOUND_SHOULD_PAUSE]; /* FIXME */ if ([(NSConditionLock*)_private[2] tryLock] != YES) { return NO; } [[(NSConditionLock*)_private[2] unlockWithCondition: SHOUND_SHOULD_PLAY]; return YES; } - (BOOL) resume { if ([(NSConditionLock*)_private[2] condition] == SOUND_SHOULD_PLAY) { return NO; } if ([(NSConditionLock*)_private[2] tryLock] == NO) { return NO; } [(NSConditionLock*)_private[2] unlockWithCondition: SOUND_SHOULD_PLAY]; return YES; } - (BOOL) stop { if ((NSConditionLock*)_private[2] == nil) { return NO; } /* FIXME */ _shouldStop = YES; RELEASE((NSConditionLock*)_private[2]); return YES; } - (BOOL) isPlaying { if ([(NSConditionLock*)_private[2] condition] == SOUND_SHOULD_PLAY) { return YES; } return NO; } ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
NSSound Reimplementation
OK, I started working on the NSSound side of of the reimplementation (already finished the Source and Sink protocols) today. I'm pretty much implementing this in the manner I explained in my previous e-mails. I've attached a text file with some excerpts from NSSound.h and NSSound.m. I'd like the maintainers to take a look at the ivar setup, I saw something like this in the Apple docs and thought it was a good way to mask some of the interworking of the implementation. Another thing to look into is the way I'm using the NSConditionLock to block the streaming thread. PS: Please note all the FIXME tags I just started working on this and have not even checked to see if it compiles, I just need to know I'm going in the right direction before going further. Thanks Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
OK, this is the architecture design I've come up with... FYI: I deviated slightly from what I was originally thinking. I'm going to start a thread using NSThread's -detachNewThreadWithSelector:toTarget:withObject: which will have a while loop in it that streams the audio data. I figured the playback methods should just command the thread... -play starts the thread, -stop cancels it, -pause blocks it, and -resume unblocks it (I'm still not sure how I'll manage to do this). So here's what I have, as far as interfaces go (i'm only presenting relevant methods): GSSoundInput: + (BOOL)canInitWithSound: (NSSound *)aSound Will verify this bundle can open the sound (be it raw, wav, ogg, mp3, etc) - (id)initWithSound: (NSSound *)aSound Will initialize the sound data for playback - (NSUInteger)readBytes: (void *)bytes length: (NSUInteger)length Reads the data These next few match 1-to-1 with NSSound's methods and will be called by NSSound... - (NSTimeInterval)duration - (void)setCurrentTime: (NSTimeInterval) - (NSTimeInterval)currentTime These are straight forward... - (NSUInteger)bitsPerSample - (NSUInteger)channelCount - (NSUInteger)sampleRate - (NSByteOrder)byteOrder GSSoundOutput: - (id) initWithBits: (NSUInteger)bitsPerSample channels: (NSUInteger)channelCount sampleRate: (NSUInteger)sampleRate byteOrder: (NSByteOrder)byteOrder Initializes the device for playback with this info (see GSSoundInput's methods) - (BOOL)open -initWithBits:... doesn't actually open the device, this does. - (BOOL)close Closes the device - (NSUInteger)writeBytes: (void *)bytes length: (NSUInteger)length Writes the data to the device (keep in mind the device can be anything that accepts data, like a NSData object). These next few match 1-to-1 with NSSound's methods and will be called by NSSound... - (void)setVolume: (float)volume - (float)volume - (NSString *)playbackDeviceIdentifier - (void)setPlaybackDeviceIdentifier: (NSString *)playbackDeviceIdentifier - (NSArray *)channelMapping - (void)setChannelMapping: (NSArray *)channelMapping NSSound: - (id)initWithContentsOfFile:(NSString *)path byReference:(BOOL)byRef Loads file in path using NSData's -initWithContentsOfMappedFile: - (id)initWithData:(NSData *)data Finds GSSoundInput and GSSoundOutput compatible bundles and initializes them. - (BOOL)pause Blocks the thread. - (BOOL)play Makes sure there's no stream thread running for this NSSound and starts one. - (BOOL)resume Unblocks/resume the thread. - (BOOL)stop Tell the thread to exit. - (BOOL)isPlaying If stream thread exists and is unblocked will return YES, otherwise NO. - (void)_stream This is where the stream loop actually occurs. Is this a sensible design? I'm not sure this is the best way to go, but it's the best I could come up with so far and I'd really like some feedback. Like I mentioned before, I'm not really sure how to block and unblock the thread, so I'll need some help there (the Apple docs are really confusing with the whole thread thing, specially with the this is how you do it... you can also do it this way with 10.5 but we don't recommend it since it's new). Stefan ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
OK, this has been out for almost a week now and I think it's time to start responding to some of the comments/suggestions brought up. CHOOSING INPUT/OUTPUT DEVICE This is a pretty reasonable request, specially since it's part of the API (check -setPlaybackDeviceIdentifier:), the problem here is that I'm not sure what to expect! I don't have a Mac, and the API only explains that the input must be a NSString (Unique identifier of a sound output device.). I can say right away that Libao doesn't not support this feature. STREAMING David, I can see where you're coming from, however, since 10.5 NSSound uses either CoreAudio or QTKit to play sound (... this class may use either Core Audio or QuickTime to handle the actual playback.), meaning NSSound can be used for this purpose. THREADING I guess I just want to make sure that I'm allowed to use threading on the core GNUstep libraries? I didn't see a single objection to libao and the plug-in based architecture. In my head, I've split NSSound into 4 different parts: NSSound: will manage the other 3 modules; GSSoundThread (NSThread subclass): will do the actual streaming; GSSoundInput: a category that will define a standard interface to read audio data; GSSoundOutput: same as GSSoundInput but for output. The attached text file is my first attempt at defining how NSSound will communicate. I've been reading up on NSThread and it would seem that since 10.5 NSThread can be subclassed, override -main and call -start to start the thread. Will I be allowed to use this mechanism? As always, all comments/suggestions are welcome and appreciated. Stefan NSSound_arch Description: Binary data ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
Am 11.06.2009 um 23:13 schrieb Stefan Bidigaray: CHOOSING INPUT/OUTPUT DEVICE This is a pretty reasonable request, specially since it's part of the API (check -setPlaybackDeviceIdentifier:), the problem here is that I'm not sure what to expect! I don't have a Mac, and the API only explains that the input must be a NSString (Unique identifier of a sound output device.). I can say right away that Libao doesn't not support this feature. look at http://code.google.com/p/telephone/ there is example code. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSSound Reimplementation
On 7 Jun 2009, at 02:10, Christopher Armstrong wrote: Hi Stefan I don't purport to be an expert on sound APIs, but I've played around a lot with asynchronous APIs (marshalling in Java with Swing and multithreaded APIs). On 07/06/2009, at 2:01 AM, gnustep-dev-requ...@gnu.org wrote: * PulseAudio - Pros: Cross-platform, Powerful/large API, used by the GNOME project, a simple API is available, is a sound server. Cons: Requires a dedicated mainloop for the asynch API, I still don't understand how it works (the asynch API, the simple API is pretty straight forward). Calling PulseAudio cross-platform is a stretch. As far as I can tell, it works moderately-well with Ubuntu, less-well with other Linux distributions, and is a mess everywhere else. Looking at pulse audio's documentation, it appears that with the asynchronous API, you call some functions which run an exclusive event loop for pulseaudio on a separate thread. I'm not sure if you will need to spawn a separate thread for them, or if they start a thread themselves. You could alternatively integrate with the poll() mechanism, which may be simpler or more difficult depending on what GNUstep uses. See NSFileHandle for how to get notifications from file descriptors. David A. also mentioned the possibility of a streaming architecture, which I like because it makes NSSound a lot more useful. With current NSSound code, and my original submission, NSSound simply read the file/data whole, storing it in a NSData object and later playing that. Streaming would allow us to keep nothing but a pointer to the file/data (still in a NSData object) and decoding it as we're playing. This is the design of all sound applications I've had the pleasure of using. A streaming architecture sounds like a good idea, even if it requires some extra plumbing, like an NSData subclass. This way we know we can scale to large files e.g. alot of MP3 music I have is whole sets that run upto 2 hours long (~100-300MB), and this would be impractical to load completely into memory. This is what mmap() is for. NSData already has a subclass on GNUstep that wraps mmap(), so you only need 300MB of address space - not excessive even on a 32-bit platform - and the OS will handle loading and evicting the data when required. If you need a streaming API, you shouldn't be using NSSound, you should be using something like Étoilé's MediaKit or Apple's QTKit. MY OPINION No matter what I do, it looks like a separate thread is going to have to be spawned to do the streaming. Problem there is that I've never programmed with threads before, interesting for me since it'll be a learning experience. The easiest library to use is libao, it includes output every thing out there (from ALSA to PulseAudio to WINMM). OpenAL is also very nice, but it's asynchronous by design and doesn't lend it self very well for streaming. I also really like the idea of loadable bundles/plug- ins, this would allow quite a bit of flexibility, not only to GNUstep but to the application programmer. Lastly, moving the code to GNUstep-back, like suggested by David C., seems like a good idea (specially with the plug-in based setup) removing the dependency on the -gui library but pushing it over to -back. A plugable architecture would be ideal. On platforms where the kernel exposes a sane interface (e.g. FreeBSD, Solaris) you don't have any extra dependencies, because the OSS APIs are just open()/read()/ write()/ioctl() calls on the device[1]. On platforms with a second- rate sound subsystem in the kernel you can fall back to something like libao. David [1] See: http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Frameworks/MediaKit/oss.m?rev=3470 ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
NSSound Reimplementation
I guess I've been making a lot of noise about this lately, fact is I'm kind of bored! Anyway, as most of you know, I've put some code out recently and got quite a bit of feedback. Reading some of the comments I realized I hadn't thought this through as much as I had initially thought. In this e-mail I'm going to put forth some ideas for the reimplementation of NSSound and would really appreciate the community's opinion to make a better decision on the way to go. I know it's long, sorry but I do have a tendency of doing that! INPUT I think this one is pretty obvious, I moved the code to libsndfile from libaudiofile. Since version 1.12 libsndfile has provided a method to read directly from memory allowing NSSound to read NSData objects, and since version 1.18 has supposed Vorbis and FLAC decoding. Please read OTHER CONSIDERATIONS before commenting on this choice. OUTPUT This has probably been my biggest mistake so far. I'm providing a list of all possible audio output libraries/servers that I've researched below. Please keep in mind NSSound is very simple in design, so it does not need an all powerful output API. * JACK - Pros: JACK2 is cross-platform, very powerful API, low latency, plays well with other JACK apps, is a sound server. Cons: JACK1 (the current stable release) only works on POSIX systems, is a relatively large library (many unneeded features), requires floating point data, JACK2 is still experimental. * PulseAudio - Pros: Cross-platform, Powerful/large API, used by the GNOME project, a simple API is available, is a sound server. Cons: Requires a dedicated mainloop for the asynch API, I still don't understand how it works (the asynch API, the simple API is pretty straight forward). * OpenAL - Pros: Cross-platform, powerful and simple API, asynchronous by design. Cons: Asynchronous (I know it's here twice, but it can also be a bad thing if you're trying to stream data), requires 8 or 16 bit PCM data. * Libao - Pros: Cross-platform, extremely simple API. Cons: can only stream data. * Rolling our own / gnustep_sndd - Pros: GNUstep has full control of the API. Cons: Gnustep_sndd reinvents the wheel, any other approach would require GNUstep to implement and maintain working code for at least ALSA, OSS and WINMM/DirectSound. * Honorable mentions: ESD (UNIX-based systems only, on it's way out), aRts (on it's way out), PortAudio (David C. has mentioned it's quite unusable anywhere but Linux), SDL and NAS (seems to be a great sound server and API, but only works on *nix or requires Cgywin). REQUIREMENTS Obviously, the main requirement here is API compatibility with OS X 10.5. David A. also mentioned the possibility of a streaming architecture, which I like because it makes NSSound a lot more useful. With current NSSound code, and my original submission, NSSound simply read the file/data whole, storing it in a NSData object and later playing that. Streaming would allow us to keep nothing but a pointer to the file/data (still in a NSData object) and decoding it as we're playing. This is the design of all sound applications I've had the pleasure of using. OTHER CONSIDERATIONS * Loadable bundles/plug-ins - I thought this would be a great idea. Allow for loadable input and output bundles so that we can read from virtually any file format and output to virtually anything. Could eventually take us in the roll our own backend model, but I'm not sure this is a bad thing, yet. * Raw data reading - This seemed like a popular suggestion, and does sound useful for anyone trying to play something like a CD using NSSound. Apple seems solves this problem by having CoreAudio and QT there to pickup the slack, but we just don't have that option. * Per NSSound volume control - This is probably the hardest thing to do. Most of the libraries mentioned above do not support it. Some hacking can be done, but it won't be pretty. * Fallback if libsndfile not present - This really isn't a problem if a plug-in method is use. MY OPINION No matter what I do, it looks like a separate thread is going to have to be spawned to do the streaming. Problem there is that I've never programmed with threads before, interesting for me since it'll be a learning experience. The easiest library to use is libao, it includes output every thing out there (from ALSA to PulseAudio to WINMM). OpenAL is also very nice, but it's asynchronous by design and doesn't lend it self very well for streaming. I also really like the idea of loadable bundles/plug-ins, this would allow quite a bit of flexibility, not only to GNUstep but to the application programmer. Lastly, moving the code to GNUstep-back, like suggested by David C., seems like a good idea (specially with the plug-in based setup) removing the dependency on the -gui library but pushing it over to -back. I appreciate any and all comments/suggestions. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org
Re: NSSound Reimplementation
Hi Stefan I don't purport to be an expert on sound APIs, but I've played around a lot with asynchronous APIs (marshalling in Java with Swing and multithreaded APIs). On 07/06/2009, at 2:01 AM, gnustep-dev-requ...@gnu.org wrote: I guess I've been making a lot of noise about this lately, fact is I'm kind of bored! Anyway, as most of you know, I've put some code out recently and got quite a bit of feedback. Reading some of the comments I realized I hadn't thought this through as much as I had initially thought. In this e-mail I'm going to put forth some ideas for the reimplementation of NSSound and would really appreciate the community's opinion to make a better decision on the way to go. I know it's long, sorry but I do have a tendency of doing that! * PulseAudio - Pros: Cross-platform, Powerful/large API, used by the GNOME project, a simple API is available, is a sound server. Cons: Requires a dedicated mainloop for the asynch API, I still don't understand how it works (the asynch API, the simple API is pretty straight forward). Looking at pulse audio's documentation, it appears that with the asynchronous API, you call some functions which run an exclusive event loop for pulseaudio on a separate thread. I'm not sure if you will need to spawn a separate thread for them, or if they start a thread themselves. You could alternatively integrate with the poll() mechanism, which may be simpler or more difficult depending on what GNUstep uses. The main GNUstep GUI loop will need to use pulseaudio lock functions before calling pulseaudio APIs. Callbacks which send data back to GNUstep will need to respect the single-threaded nature of the GNUstep GUI thread, which means that the code they call must execute on the GNUstep run loop, not the pulseaudio one. The only exception to this is passing data back: in the callback function, you may need to copy the data that pulseaudio gives you into a GNUstep data structure (NSString, NSData, etc) and pass that back to the main GNUstep run loop. The GNUstep data structure will obviously need to be instantiated in the callback, which means that its one of the thread- safe GNUstep APIs. Reading the pulseaudio documentation, it does appear that you have to use its locking functions before calling into its API, but this shouldn't pose much of an issue if you follow the rules. For callback functions, I would expect you'd use something like NSRunLoop's - performSelector:target:argument:order:modes: method to marshall a call back into the main GNUstep GUI loop). The dedicated main loop running on a separate thread should pose less of a problem than something that needs constant access to the main thread. As long as you can post messages into its event loop, and the event loop is fairly responsive, everything should operate smoothly. IMHO the most important thing to remember with these sorts of APIs is that the other thread can be in an inconsistent state compared to your thread, so you just need a little bit of extra state checking e.g. if you send a stop command to the other thread whilst it is playing, it may not stop synchronously, so if you try sending stop again, make sure that the API either ignores it, or make sure you can catch any exceptions or error codes if it is already stopped. David A. also mentioned the possibility of a streaming architecture, which I like because it makes NSSound a lot more useful. With current NSSound code, and my original submission, NSSound simply read the file/data whole, storing it in a NSData object and later playing that. Streaming would allow us to keep nothing but a pointer to the file/data (still in a NSData object) and decoding it as we're playing. This is the design of all sound applications I've had the pleasure of using. A streaming architecture sounds like a good idea, even if it requires some extra plumbing, like an NSData subclass. This way we know we can scale to large files e.g. alot of MP3 music I have is whole sets that run upto 2 hours long (~100-300MB), and this would be impractical to load completely into memory. MY OPINION No matter what I do, it looks like a separate thread is going to have to be spawned to do the streaming. Problem there is that I've never programmed with threads before, interesting for me since it'll be a learning experience. The easiest library to use is libao, it includes output every thing out there (from ALSA to PulseAudio to WINMM). OpenAL is also very nice, but it's asynchronous by design and doesn't lend it self very well for streaming. I also really like the idea of loadable bundles/plug- ins, this would allow quite a bit of flexibility, not only to GNUstep but to the application programmer. Lastly, moving the code to GNUstep-back, like suggested by David C., seems like a good idea (specially with the plug-in based setup) removing the dependency on