Re: FSMountServerVolumeAsync() in multiple threads?
Re: FSMountServerVolumeAsync() in multiple threads?
- Subject: Re: FSMountServerVolumeAsync() in multiple threads?
- From: Jim Luther <email@hidden>
- Date: Wed, 12 Aug 2009 11:47:41 -0700
On Aug 11, 2009, at 5:28 PM, Matt DeFoor wrote:
I have an application where I'm trying to mount multiple volumes in
their own thread using FSMountServerVolumeAsync(). The application is
Cocoa-based. So, I use:
[NSThread detachNewThreadSelector:@selector(mountResource:)
toTarget:self withObject:aResource]
to spawn each thread. The call to FSMountServerVolumeAsync() looks
like this:
Result = FSMountServerVolumeAsync((CFURLRef)urlOfVolumeToMount, NULL,
(CFStringRef)[aResource username], (CFStringRef)[aResource password],
volumeOp, aResource, 0, mountUPP, CFRunLoopGetCurrent(),
CFSTR("MyMountMode"));
As you can tell, I'm using a callback. It handles certain aspects of
what is returned. When, I have only one thread, things work fine; the
callback is called and the volume is mounted. When I have more than
one volume to mount (ergo, more than one thread is calling
FSMountServerVolumeAsync()) varying results are produced. For example,
the return code from FSMountServerVolumeAsync() might be -50. Or there
might be an exception (EXC_BAD_ACCESS) in one of the functions that
FSMountServerVolumeAsync() calls (e.g. TAFPSession::AFPLogout).
Has anyone had success using FSMountServerVolumeAsync() in this
manner?
Is there a better approach to FSMountServerVolumeAsync()'s usage?
Thanks,
Matt
P.S. Jim Luther suggest that I post here instead of the
macnetworkprog list.
Matt,
I slapped together a quick tool that calls FSMountServerVolumeAsync()
on multiple threads. I didn't find that FSMountServerVolumeAsync
crashes or returns errors (well... it will return errors if there's
really a problem).
I've pasted the source for my tool below (you'll have to change
gMountInfos to the URLs you are using). Maybe it will help you figure
out why your code doesn't work.
- Jim
#include <CoreServices/CoreServices.h>
#include <pthread.h>
struct MountInfo {
const char *url;
const char *user;
const char *password;
};
// array of server URLs to mount with usernames and passwords
const struct MountInfo gMountInfos[] = {
{"afp://foo1.bar/volume", "user1", "password1"},
{"afp://foo2.bar/volume", "user2", "password2"},
{"afp://foo3.bar/volume", "user3", "password3"},
{NULL, NULL, NULL}, // mark the end with NULLs
};
static void FSVolumeMountProc(FSVolumeOperation volumeOp, void
*clientData, OSStatus err, FSVolumeRefNum mountedVolumeRefNum)
{
Boolean *inProgress = (Boolean *)clientData;
// all we're doing is setting inProgress (what clientData points to)
to err so the tool can fall out of the wait loop.
*inProgress = FALSE;
}
static void DoMountServer(void *arg)
{
struct MountInfo *mountInfo;
pthread_t tid;
CFURLRef url = NULL;
CFStringRef user = NULL;
CFStringRef password = NULL;
OSStatus status;
FSVolumeMountUPP callback;
CFRunLoopRef runloop;
FSVolumeOperation volumeOp;
FSMountStatus mountStatus;
OSStatus volumeOpStatus;
FSVolumeRefNum mountedVolumeRefNum;
Boolean inProgress;
mountInfo = (struct MountInfo *)arg;
tid = pthread_self();
printf("[%p] mounting \'%s\', \'%s\', \'%s\'\n", tid, mountInfo->url,
mountInfo->user, mountInfo->password);
fflush(stdout);
// create the CF objects from the c strings */
url = CFURLCreateWithBytes(kCFAllocatorDefault, (UInt8 *)mountInfo-
>url, (CFIndex)strlen(mountInfo->url), kCFStringEncodingUTF8, NULL);
if ( url != NULL ) {
if ( strlen(mountInfo->user) ) {
user = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)
mountInfo->user, (CFIndex)strlen(mountInfo->user),
kCFStringEncodingUTF8, FALSE);
}
if ( strlen(mountInfo->password) ) {
password = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)
mountInfo->password, (CFIndex)strlen(mountInfo->password),
kCFStringEncodingUTF8, FALSE);
}
// create the callback UPP
callback = NewFSVolumeMountUPP(FSVolumeMountProc);
// get the current runloop to run on
runloop = CFRunLoopGetCurrent();
// create the volume operation
status = FSCreateVolumeOperation(&volumeOp);
if ( status == noErr ) {
// start the asynchronous mount
inProgress = TRUE; // set inProgress to "in progress"
status = FSMountServerVolumeAsync(url, NULL, user, password,
volumeOp, (void *)&inProgress, kNilOptions, callback, runloop,
kCFRunLoopDefaultMode);
if ( status == noErr ) {
// wait loop -- wait for inProgress to be FALSE
do
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 5.0, true);
} while ( inProgress );
status = FSGetAsyncMountStatus(volumeOp, &mountStatus,
&volumeOpStatus, &mountedVolumeRefNum, NULL);
if ( status == noErr ) {
printf("[%p] mountStatus = %d; volumeOpStatus = %d;
mountedVolumeRefNum = %hd\n", tid, mountStatus, volumeOpStatus,
mountedVolumeRefNum);
}
}
FSDisposeVolumeOperation(volumeOp);
}
if ( password != NULL ) {
CFRelease(password);
}
if ( user != NULL ) {
CFRelease(user);
}
CFRelease(url);
}
return;
}
int main (int argc, const char * argv[])
{
// make the threadID array big enough for all tids
pthread_t threadID[(sizeof(gMountInfos) / sizeof(struct MountInfo)) -
1];
int index;
index = 0;
// start a thread for each element in gMountInfos
while (gMountInfos[index].url != NULL) {
if ( pthread_create(&threadID[index], NULL, (void *)DoMountServer,
(void *)&gMountInfos[index]) != 0 ) {
return ( EXIT_FAILURE );
}
++index;
}
// wait for all threads to complete
while ( index >= 0 ) {
pthread_join(threadID[index], NULL);
--index;
}
printf("done\n");
return ( EXIT_SUCCESS );
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Filesystem-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden