• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: FSMountServerVolumeAsync() in multiple threads?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: FSMountServerVolumeAsync() in multiple threads?


  • Subject: Re: FSMountServerVolumeAsync() in multiple threads?
  • From: Jim Luther <email@hidden>
  • Date: Thu, 13 Aug 2009 14:39:56 -0700

I replaced:
	// wait for all threads to complete
	while ( index >= 0 ) {
		pthread_join(threadID[index], NULL);
		--index;
	}
with:
	sleep(10);

(the AFP server volumes I was testing with mounted in less than 10 seconds). You can try the same in your code. That takes pthread_join out of the mix. Still no crashes for me. I tried this with both Leopard (PowerPC system) and SnowLeopard (Intel system).

You're going to have to provide a small application/tool that reproduces the problems with your bug report.

- Jim

On Aug 13, 2009, at 2:04 PM, Matt DeFoor wrote:

Jim - Thanks for the sample code! It has helped quite a bit! I think
that it has helped me identify some potential bugs in
FSMountServerVolumeAsync(). The bugs appear to be related to the
protocol being used and whether or not the thread is detached. In my
application, all threads are created by NSThread and are thus,
detached. The only way that I can get reliable mounting of AFP volumes
via threaded calls to FSMountServerVolumeAsync() is to start the
thread and then join it to the creating thread (just like in your
sample). If you do not call pthread_join(), then you get varying
results from out right failures (-50, -36, to name a few) to crashes.

My understanding of pthread_join() is that it joins the detached
thread to the thread it is called from and the calling thread waits
for the newly created thread to finish. This is somewhat counter
productive to the usage of FSMountServerVolumeAsync() when the server
is unavailable. It makes the calling thread block. You might want to
try this and see if you can reproduce these results. I've tried it
with your code on two different AFP servers (AFP on Mac OS X Server
and AFP on NetWare) to see if one behaves different than the other.
They do not. They both produce sporadic results and failures.

Anyway, I wanted to let you know what my findings were. It sounds like
I need to file a bug...unless there are other suggestions.

Cheers,
Matt

On Wed, Aug 12, 2009 at 2:47 PM, Jim Luther<email@hidden> wrote:
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

_______________________________________________ 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
References: 
 >FSMountServerVolumeAsync() in multiple threads? (From: Matt DeFoor <email@hidden>)
 >Re: FSMountServerVolumeAsync() in multiple threads? (From: Jim Luther <email@hidden>)
 >Re: FSMountServerVolumeAsync() in multiple threads? (From: Matt DeFoor <email@hidden>)

  • Prev by Date: Re: FSMountServerVolumeAsync() in multiple threads?
  • Next by Date: Mounting Hybrid discs...
  • Previous by thread: Re: FSMountServerVolumeAsync() in multiple threads?
  • Next by thread: Mounting Hybrid discs...
  • Index(es):
    • Date
    • Thread