Disk Arbitration Objective C: Put All Drives and Partitions in an Array - objective-c

I am just starting out in this wacky world of programming and I have come across a very frustrating problem:
I am trying to use Disk Arbitration Framework to put all Disks in a array.
#import "DiskDetector.h"
#import "Disk.h"
#implementation DiskDetector
-(id)init {
self.arrayOfDisks = [[NSMutableArray alloc]init];
DASessionRef session;
session = DASessionCreate(kCFAllocatorDefault);
DARegisterDiskAppearedCallback(session, kDADiskDescriptionMatchVolumeMountable,diskAppearedCallback,NULL);
DARegisterDiskDisappearedCallback(session,kDADiskDescriptionMatchVolumeMountable, diskDisappearedCallback, NULL);
DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
return self;
}
-(void)addToArrayOfDisks:(Disk*)disk {
}
void diskAppearedCallback(DADiskRef disk, void* context)
{
Disk *theDisk = [[Disk alloc]initWithNewDisk:disk];
NSLog(#"Disk Name: %#",theDisk.diskName);
NSLog(#"Disk Number: %#",theDisk.diskBSDName);
NSLog(#"Disk Connection Type: %#",theDisk.diskConnection);
NSLog(#"Disk Capacity in Bytes: %#",theDisk.diskTotalCapacityInBytes);
NSLog(#"Volume Name: %#",theDisk.partitionScheme);
//How Do I return "theDisk" from this function?
//[self.arrayOfDisks addObject:theDisk] does not work...complier has problem with use of "self"
}
void diskDisappearedCallback(DADiskRef disk, void* context)
{
NSLog(#"%s was ejected", DADiskGetBSDName(disk));
}
#end
As you can see, everything logs okay. The issue is that I want to return "theDisk" object in some way So I can work with it.
Since the callback function is void, I cannot do a return statement. If I attempt to modify the function's return type the DARegisterDiskAppearedCallback Function will not work entirely.
Again, my only goal here is to get information about all disks and partitions on computer and put them in an array so I can get info about them and manipulate them.
Also, can anyone explain when one would put something in "(void*)context" in the callback function? Apple Documentation is very vague on this...or maybe I am missing something entirely

The context parameter is for your use. You can set whatever you want as the context, and DiskArbitration will pass it to you when it calls the callback. You can use this to solve your first problem by passing your DiskDetector object as the context:
-(id)init {
// ...
DARegisterDiskAppearedCallback(session, kDADiskDescriptionMatchVolumeMountable, diskAppearedCallback, self);
// ...
}
void diskAppearedCallback(DADiskRef disk, void* context) {
DiskDetector *detector = (DiskDetector *)context;
// ...
[detector.arrayOfDisks addObject:theDisk];
}

Related

Why can setting a Block variable inside an if statement cause a carsh?

I found an block example in the book "Effective Objective-C 2.0"
void (^block)();
if (/* some condition */) {
block = ^ {
NSLog(#"Block A");
};
} else {
block = ^ {
NSLog(#"Block B");
};
}
block();
The code is dangerous, and here is the explanation in the book:
The two blocks that are defined within the if and else statements are allocated within stack memory. When it allocates stack memory for each block, the compiler is free to overwrite this memory at the end of the scope in which that memory was allocated. So each block is guaranteed to be valid only within its respective if-statement section. The code would compile without error but at runtime may or may not function correctly. If it didn’t decide to produce code that overwrote the chosen block, the code would run without error, but if it did, a crash would certainly occur.
I don't understand the meaning of "If it didn’t decide to produce code that overwrote the chosen block, the code would run without error, but if it did, a crash would certainly occur."
Can someone explain and give examples?
The issue is similar to that of a C array being created locally to a function and then used after the function returns:
#import <Foundation/Foundation.h>
dispatch_block_t global_block;
int * global_arr;
void set_globals(void)
{
if( YES ){
global_block = ^{
NSLog(#"Summer is butter on your chin and corn mush between every tooth.");
};
int arr[5] = {1, 2, 3, 4, 5};
global_arr = arr;
}
}
void write_on_the_stack(int i)
{
int arr[5] = {64, 128, 256, 512, 1024};
int v = arr[3];
dispatch_block_t b = ^{
int j = i + 10;
j += v;
};
b();
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
set_globals();
write_on_the_stack();
global_block();
NSLog(#"%d", global_arr[0]); // Prints garbage
}
return 0;
}
The space on the stack that was used to store the values of the array may be re-used for any purpose. I use the separate function here because it most reliably demonstrates the problem. For your exact case, with the if block and the access in the same function, the compiler is still free to re-use the stack space. It may not, but you can't rely on that. You're breaking the scope rules of the language (derived from C).
As Jesse Rusak and CrimsonChris pointed out in comments, though, with a Block-type variable compiled under ARC, the Block is created on the stack like the array, but copied off the stack (to the heap) when it's stored in a strong pointer. All object pointers, including your global, are strong by default.
If you were not compiling with ARC, this would be unreliable. I can't come up with a failing example with my current compiler, but again, it's breaking the rules and the compiler is under no obligation to do what you want.
Essentially what this is saying is that if there's code running on a separate thread, and something gets assigned to the area of memory currently used by block but before the block() call, then bad things will happen.
void (^block)();
if (/* some condition *)) {
block = ^ {
NSLog(#"Block A");
}
} else {
block = ^ {
NSLog(#"Block B");
}
}
<--- another thread overwrites the **block** block
block(); <--- runtime error since **block** has been dereferenced.

Callback when a block is deallocated

I am calling into Cocoa from C, all through the Obj-C runtime.
I am able to create block objects with the info from here[1] and pass them as arguments to Cocoa methods which retain them as needed, and release them when they are no longer needed. The problem is that I need to release other resources associated with the block when the block reaches refcount 0 and is deallocated, so I need a way to set a callback for when that happens.
With normal objects, I would just subclass and override dealloc(). I hear blocks are objects too - is there a Block class that can be subclassed? Or is there any other way to hook up a function on release and/or dealloc of blocks?
Thanks.
[1] http://clang.llvm.org/docs/Block-ABI-Apple.html
You can use the Obj-C Associated Objects API to associate an object instance with a block instance. The associated object will (if it is not accessed anywhere else) be deallocated when the block is deallocated.
Use the -dealloc method of the associated object to execute any desired resource cleanup, etc.
Expanding on my comment:
I'll assume you are using the Clang compiler to create your blocks in C, if you are creating the block description structs yourself the idea is the same but you can create the structs directly with the correct values.
If you wish to call a cleanup function when a block is disposed of then (in outline):
if (bObject->flags & BLOCK_HAS_COPY_DISPOSE)
{
// block already has a dispose helper
// save current dispose helper in a lookup table with key the bObject
bObject->descriptor->dispose_helper = function which:
a) uses the lookup table to call the original helper
b) removes the entry from the lookup table
c) calls your cleanup function
}
else
{
// block does not have a dispose helper
bObject->flags |= BLOCK_HAS_COPY_DISPOSE; // set is has helpers
bObject->descriptor->copy_helper = dummy copy function
bObject->descriptor->dispose_helper = dispose function which just calls your cleanup
}
You need a lookup table to store a map from block addresses to helper addresses, e.g. NSMapTable.
HTH
Addendum
As requested in comments my quick'n'dirty test code, it just follows the pseudo-code above. Run this and you should see the second and third blocks get disposed, the first is not as its a static literal and doesn't need disposing.
void DummyBlockCopy(void *src, void *dst)
{
}
void BlockDispose(void *src)
{
printf("BlockDispose %p\n", src);
}
typedef void (*HelperFunction)(void *);
NSMapTable *disposeHelpers;
void BlockDisposeCallExisting(void *src)
{
HelperFunction helper = (__bridge void *)[disposeHelpers objectForKey:(__bridge id)(src)];
if (helper)
{
helper(src);
[disposeHelpers removeObjectForKey:(__bridge id)(src)];
}
printf("BlockDisposeCallExisting %p\n", src);
}
void block_trap_dispose(void *aBlock)
{
BlockObject *bObject = aBlock;
if (bObject->flags & BLOCK_HAS_COPY_DISPOSE)
{
[disposeHelpers setObject:(__bridge id)(void *)bObject->descriptor->dispose_helper forKey:(__bridge id)(aBlock)];
bObject->descriptor->dispose_helper = BlockDisposeCallExisting;
}
else
{
bObject->flags |= BLOCK_HAS_COPY_DISPOSE;
bObject->descriptor->copy_helper = DummyBlockCopy;
bObject->descriptor->dispose_helper = BlockDispose;
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
disposeHelpers = [NSMapTable.alloc initWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)
valueOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)
capacity:2];
void (^b1)(void) = ^{ printf("hello world\n"); };
printf("b1: %p\n", b1);
b1();
block_trap_dispose((__bridge void *)(b1));
int x = 10;
void (^b2)(void) = ^{ printf("x is %d\n", x); };
printf("b2: %p\n", b2);
b2();
block_trap_dispose((__bridge void *)(b2));
NSObject *anObject = NSObject.new;
void (^b3)(void) = ^{ printf("anObject: %p\n", anObject); };
printf("b3: %p\n", b3);
b3();
block_trap_dispose((__bridge void *)(b3));
}
Ok, this is how I solved it.
First I created a block_literal (defined to have a block_descriptor attached).
struct block_descriptor {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct block_literal)
copy_helper_t copy_helper; // IFF (1<<25)
dispose_helper_t dispose_helper; // IFF (1<<25)
};
struct block_literal {
struct block_literal *isa;
int flags;
int reserved;
void *invoke;
struct block_descriptor *descriptor;
struct block_descriptor d; // because they come in pairs
};
This is how you should set the fields:
block.isa = _NSConcreteStackBlock //stack block because global blocks are not copied/disposed
block.flags = 1<<25 //has copy & dispose helpers
block.reserved = 0
block.invoke = my_callback_function
block.descriptor = &block.d
block.d.reserved = 0
block.d.size = sizeof(block_literal)
block.d.copy_helper = my_copy_callback
block.d.dispose_helper = my_dispose_callback
I keep a refcount per each created block which starts at 1, and which is incremented in my_copy_callback and decremented in my_dispose_callback. When the refcount reaches 0 the resources associated with the block gets released.
Note: copy/dispose helpers will not be called on synchronous methods like NSString's enumerateLinesUsingBlock because these methods don't retain/release the block while using it because they assume that the block remains available for the duration of the call. OTOH, an async method like dispatch_async() does invoke the helpers. Calling dispatch_async() multiple times on the same block should show the refcount incremented twice and then decremented.

Doing an atomic read in objective-C

I have a thread-safe class, a cancel token, that transitions from an unstable mutable state (not cancelled) to a stable immutable state (cancelled). Once an instance has become immutable, I'd like to stop paying the cost of acquiring a lock before checking the state.
Here's a simplification of what things look like now:
-(bool) isCancelled {
#synchronized(self) {
return _isCancelled;
}
}
-(bool) tryCancel {
#synchronized(self) {
if (_isCancelled) return false;
_isCancelled = true;
}
return true;
}
and what I want to try:
-(bool) isCancelled {
bool result;
// is the following correct?
// can the two full barriers be reduced to a single read-acquire barrier somehow?
OSMemoryBarrier();
result = _isCancelled != 0;
OSMemoryBarrier();
return result;
}
-(bool) tryCancel {
return OSAtomicCompareAndSwap32Barrier(0, 1, &_isCancelled);
}
Is using two memory barriers the correct approach? How should I expect it to compare to the cost of acquiring a lock (insert standard refrain about profiling here)? Is there a cheaper way to do it?
Edit: this sounds like possible premature optimization. is this lock acquisition slowing things down?
Edit2: its possible compiler optimization will defeat this. be aware.
if you are concerned about the gotchas with double checked locking, perhaps dispatch_once() could be useful for you?
would double checked locking work in this case?
-(void) doSomething {
if (!_isCanceled) { //only attempt to acquire lock if not canceled already
#synchronized(self) {
if (!_isCanceled) // now check again (the double check part)
doSomethingElse();
}
}
}
read the wikipedia entry on double checked locking for more info

How to enforce parameters of anonymous blocks to be unused in Objective-C?

I've run into a situation while using a library called TransitionKit (helps you write state machines) where I am want to supply entry and exit actions in the form of a callback.
Sadly, the callbacks include two completely useless parameters. A typical block has to look like this:
^void (TKState *state, TKStateMachine *stateMachine) {
// I TOTALLY don't want parameters `state` or `stateMachine` used here
};
(this is an anonymous code block. Read up on blocks here if you're unclear)
As I've noted in the comment, I really don't want those parameters even mentioned in the body there. I've tried simply removing the parameter names like suggested in this question like so:
^void (TKState *, TKStateMachine *) {
// I foobar all I like here
};
but sadly the code won't compile then :(.
How can I enforce this non-usage of parameters in code?
This is what I could come up with. Quite a hack and relies on the GCC poison pragma, which is not standard but a GNU extension - although, given that you are probably compiling this with clang anyway, it should not be a problem.
#define _state state
#define _stateMachine stateMachine
#pragma GCC poison state stateMachine
Then this compiles:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something();
}
But this doesn't:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something(state, stateMachine);
}
You could just have a function that took one kind of block, and returned another, like this:
#class TKState, TKStateMachine; // here so this will compile
typedef void (^LongStateBlock)(TKState *state, TKStateMachine *stateMachine);
static inline LongStateBlock Adapter(void(^block)()) {
void(^heapBlock)() = [block copy]; // forces block to be on heap rather than stack, a one-time expense
LongStateBlock longBlock = ^(TKState *s __unused, TKStateMachine *sm __unused) {
heapBlock();
};
// this is the non-ARC, MRR version; I'll leave ARC for the interested observer
[heapBlock release];
return [[longBlock copy] autorelease];
}
And in practice:
// this represents a library method
- (void)takesLongStateBlock:(LongStateBlock)longBlock
{
// which hopefully wouldn't look exactly like this
if (longBlock) longBlock(nil, nil);
}
- (void)yourRandomMethod
{
[self takesLongStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
NSLog(#"Gratuitous parameters, AAAAHHHH!");
}];
[self takesLongStateBlock:Adapter(^{
NSLog(#"So, so clean.");
})];
}
The whole thing is gisted, and should compile inside any class. It does what you expect when you call -yourRandomMethod.
AFAIK there is no way to do what you want when you are creating a block, you can only miss the parameter names when you are declaring a block variable(a reference to a block, to avoid misunderstandings)
So here you can miss the param names:
void (^myBlock)(SomeClass *);
But not when you create a block:
myBlock = ^(SomeClass *o)
{
};
I'd write
^void (TKState *unused_state, TKStateMachine *unused_stateMachine) {
// Anyone using unused_state or unused_stateMachine gets what they deserve.
};
Of course someone can use the parameters. But then whatever you do, they can change the code. If someone is intent on shooting themselves in the foot, there is no stopping them.

Is there a way to wrap an ObjectiveC block into function pointer?

I have to provide a C-style callback for a specific C library in an iOS app. The callback has no void *userData or something similar. So I am not able to loop in a context. I'd like to avoid introducing a global context to solve this. An ideal solution would be an Objective-C block.
My question: Is there a way to 'cast' a block into a function pointer or to wrap/cloak it somehow?
Technically, you could get access to a function pointer for the block. But it's totally unsafe to do so, so I certainly don't recommend it. To see how, consider the following example:
#import <Foundation/Foundation.h>
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
};
int main(int argc, char *argv[]) {
#autoreleasepool {
// Block that doesn't take or return anything
void(^block)() = ^{
NSLog(#"Howdy %i", argc);
};
// Cast to a struct with the same memory layout
struct Block_layout *blockStr = (struct Block_layout *)(__bridge void *)block;
// Now do same as `block()':
blockStr->invoke(blockStr);
// Block that takes an int and returns an int
int(^returnBlock)(int) = ^int(int a){
return a;
};
// Cast to a struct with the same memory layout
struct Block_layout *blockStr2 = (struct Block_layout *)(__bridge void *)returnBlock;
// Now do same as `returnBlock(argc)':
int ret = ((int(*)(void*, int a, ...))(blockStr2->invoke))(blockStr2, argc);
NSLog(#"ret = %i", ret);
}
}
Running that yields:
Howdy 1
ret = 1
Which is what we'd expect from purely executing those blocks directly with block(). So, you could use invoke as your function pointer.
But as I say, this is totally unsafe. Don't actually use this!
If you want to see a write-up of a way to do what you're asking, then check this out:
http://www.mikeash.com/pyblog/friday-qa-2010-02-12-trampolining-blocks-with-mutable-code.html
It's just a great write-up of what you would need to do to get this to work. Sadly, it's never going to work on iOS though (since you need to mark a page as executable which you're not allowed to do within your app's sandbox). But nevertheless, a great article.
If your block needs context information, and the callback does not offer any context, I'm afraid the answer is a clear no. Blocks have to store context information somewhere, so you will never be able to cast such a block into a no-arguments function pointer.
A carefully designed global variable approach is probably the best solution in this case.
MABlockClosure can do exactly this. But it may be overkill for whatever you need.
I know this has been solved but, for interested parties, I have another solution.
Remap the entire function to a new address space. The new resulting address can be used as a key to the required data.
#import <mach/mach_init.h>
#import <mach/vm_map.h>
void *remap_address(void* address, int page_count)
{
vm_address_t source_address = (vm_address_t) address;
vm_address_t source_page = source_address & ~PAGE_MASK;
vm_address_t destination_page = 0;
vm_prot_t cur_prot;
vm_prot_t max_prot;
kern_return_t status = vm_remap(mach_task_self(),
&destination_page,
PAGE_SIZE*(page_count ? page_count : 4),
0,
VM_FLAGS_ANYWHERE,
mach_task_self(),
source_page,
FALSE,
&cur_prot,
&max_prot,
VM_INHERIT_NONE);
if (status != KERN_SUCCESS)
{
return NULL;
}
vm_address_t destination_address = destination_page | (source_address & PAGE_MASK);
return (void*) destination_address;
}
Remember to handle pages that aren't required anymore and note that it takes a lot more memory per invocation than MABlockClosure.
(Tested on iOS)