I was working on some code that utilizes the low level file manager functions (PBxxxx) and wanted to try out the async IO capabilities, specifically using ioCompletion routines as opposed to completion polling.
The approach is straight forward: I fill out a ParamBlockRec, provide the address of a completion routine, called a low level function like PBRead, and then once the IO request completes, my completion routine is called with the a pointer to the param block record provided via the a0 register.
However, there does not seem to be any facility with these low level file manager functions to pass my own custom data (for example a pointer) which is the usual design pattern for callback routines. As it is, the only info I get in the completion routine is a pointer to the param block record. In this type of scenario, the ugly workaround is to use global variables and access the globals from the callback (completion routine). But looking at the documentation (Inside Macintosh), that won't work. Why? Because apparently the A5 register can be invalid when this completion routine is called and thus you don't have access to your application globals.
The documentation then suggests you utilize SetA5 / SetCurrentA5 so that you can access your application globals. But I'm scratching my head regarding how they expect that to work? The A5 pattern is usually to call SetCurrentA5 to get your application's A5 value (while the A5 is valid) and then during the interrupt or completion routine, you pass that saved A5 value to SetA5 (and also restore the old A5 using SetA5 at the end of your completion routine). But how do you pass the application's A5 into the completion routine (in order to use SetA5) when again the only value provided to your completion routine is the param block record?
I'm sure I can figure out a way to hack this to make it work, for example setting aside some memory that can be accessed via an offset, or stuffing a value into an unused field in the param block record, or something... but I'm stubborn and I'm trying to understand what was the "blessed" or proper way to access globals in your IO completion routine (ie. how do you actually implement the Inside Macintosh suggestion of setting the A5 so you can access globals from the completion routine)?
Has anyone worked on async low level file manager routines using a completion handler? If so, do you remember the best practice for accessing globals and/or accessing your own custom data structures from within the completion handler? Without that, there's not a lot of utility with these IO completion handlers because if you only have access to the param block record, what can you possibly do from your callback?
The approach is straight forward: I fill out a ParamBlockRec, provide the address of a completion routine, called a low level function like PBRead, and then once the IO request completes, my completion routine is called with the a pointer to the param block record provided via the a0 register.
However, there does not seem to be any facility with these low level file manager functions to pass my own custom data (for example a pointer) which is the usual design pattern for callback routines. As it is, the only info I get in the completion routine is a pointer to the param block record. In this type of scenario, the ugly workaround is to use global variables and access the globals from the callback (completion routine). But looking at the documentation (Inside Macintosh), that won't work. Why? Because apparently the A5 register can be invalid when this completion routine is called and thus you don't have access to your application globals.
The documentation then suggests you utilize SetA5 / SetCurrentA5 so that you can access your application globals. But I'm scratching my head regarding how they expect that to work? The A5 pattern is usually to call SetCurrentA5 to get your application's A5 value (while the A5 is valid) and then during the interrupt or completion routine, you pass that saved A5 value to SetA5 (and also restore the old A5 using SetA5 at the end of your completion routine). But how do you pass the application's A5 into the completion routine (in order to use SetA5) when again the only value provided to your completion routine is the param block record?
I'm sure I can figure out a way to hack this to make it work, for example setting aside some memory that can be accessed via an offset, or stuffing a value into an unused field in the param block record, or something... but I'm stubborn and I'm trying to understand what was the "blessed" or proper way to access globals in your IO completion routine (ie. how do you actually implement the Inside Macintosh suggestion of setting the A5 so you can access globals from the completion routine)?
Has anyone worked on async low level file manager routines using a completion handler? If so, do you remember the best practice for accessing globals and/or accessing your own custom data structures from within the completion handler? Without that, there's not a lot of utility with these IO completion handlers because if you only have access to the param block record, what can you possibly do from your callback?




