Sharing a file pointer/handle with another task

Discussion to talk about software related topics only.
Post Reply
sswope
Posts: 7
Joined: Thu Jan 22, 2009 10:10 am

Sharing a file pointer/handle with another task

Post by sswope »

Let's say I have 2 tasks, A and B. The file system has been initialized. Each of the tasks has called f_enterfs.

Task A opens a file, obtaining the file pointer/handle. Task A passes the file pointer/handle to task B.

Task B uses the file pointer/handle to perform some I/O, and then closes the file.

Will this work ok, or will it mess up the file system ?
User avatar
pbreed
Posts: 1088
Joined: Thu Apr 24, 2008 3:58 pm

Re: Sharing a file pointer/handle with another task

Post by pbreed »

I don't know the answer,
but could the task pass the file name instead and then there is no issue....
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: Sharing a file pointer/handle with another task

Post by rnixon »

I'm not positive, but I thought the purpose of the fs_enter was to set the file path for each task. If that's the case, then passing just the handle might have a problem. Have you tried it?
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: Sharing a file pointer/handle with another task

Post by tod »

Based on an old post by Ridgeglider you also have to remember to call f_chdrive() in each task.

A more recent post also discussed issues with multi-task handling via a file pointer, I don't think the thread has a final resolution but maybe Ridge or v8dave will chime in with what they learned.

Considering it seems the code uses the task priority as a unique ID to create and reference data structures for each task, I would think it would be somewhat dangerous to pass file handles among tasks, but I'm an admitted neophyte to this particular area of NB programming.
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: Sharing a file pointer/handle with another task

Post by rnixon »

I think it might be cleaner and more robust to do the writes in just one task. Otherwise task A could be writing data to the file, then task B is handed the file handle and starts writing as well, the data will be mixed will it not? If one task did the writing and semaphores were used to control the resource, then multiple tasks could share the file resource (by pending) and avoid any corruption of data.
sswope
Posts: 7
Joined: Thu Jan 22, 2009 10:10 am

Re: Sharing a file pointer/handle with another task

Post by sswope »

pbreed wrote: I don't know the answer,
but could the task pass the file name instead and then there is no issue....

Until I know the answer, I think that's the direction I will be forced to take.

---------------
rnixon wrote: ... passing just the handle might have a problem. Have you tried it?

The handle should point to the necessary structures for performing the I/O, making me think that it should work. I have not tried it yet. However, if it does 'work', that would not prove that it would always work, or that it did not cause damage.

---------------
tod wrote: ... you also have to remember to call f_chdrive() in each task .... but I'm an admitted neophyte to this particular area....

Sorry, I should have included f_chdrive() in the original post. Looks like you're not the only one (neophyte). At least I'm in good company.
sswope
Posts: 7
Joined: Thu Jan 22, 2009 10:10 am

Re: Sharing a file pointer/handle with another task

Post by sswope »

rnixon wrote: ... task A could be writing data to the file, then task B is handed the file handle and starts writing as well, the data will be mixed will it not?

I apologize for omitting some detail. In my application, task A would pass the handle to task B after task A had finished using the handle.
Ridgeglider
Posts: 513
Joined: Sat Apr 26, 2008 7:14 am

Re: Sharing a file pointer/handle with another task

Post by Ridgeglider »

I agree with rnixon and, without some detailed testing, would encourage you to pass data from TaskA and TaskB to a single TaskC that consolidates the data and then writes it to a file in a more uniform manner than having two tasks just writing data to the same file via an open handle. Actually, I might even be more conservative and write TaskA data to one file, and TaskB data to another and consolidate them offline. That would be the safest. If a merged file is essential, consider these issues:

The shared handle route, or the even passing the entire path seems problematic to me. You might also consider using individual semaphores or OS_FLAG bits posted (or set in the case of flag bits) from TaskA and TaskB to trigger write events pended on in Task C. With all four of these methods, I suspect you will run into issues related to the order that data gets written to the files. Assume for example that both TaskA and TaskB post individual semaphores to trigger a file write event with the idea that the data itself is passed from TaskA or TaskB to TaskC by two corresponding references (perhaps passed into TaskC when taskC is created). With all four strategies, there is no easy guarantee on which event will be written to the file first: the answer has more to do w/respective task PRIOs and which task is active at a given instant than on which data occurred first and was therefore to be logged 1st. This is even more true if the source of the data comes from some input, say a uart with a buffer that needs to be serviced by TaskA when its PRIO and the other task loads dictates that taskA runs.

With the shared handle route, what happens if two tasks are trying to write a chunk of data at the same time? Usually, tasks use some form of write() calls, instead of writeall() calls so that they can block when the file_writing recipient can't write all the data at once. These scenarios set up the stage for very confused, interleaved, merged data unless you also start locking tasks.

With the pass the handle approach, I can also imagine issues with opening or closing the files: Do both tasks have an updated handle for a new file, or do they have the old handle still?

If the order of the written data's important, it seems to me that perhaps TaskA and TaskB could post their data, (embedded in a struct perhaps?) into a single fifo that TaskC pends on and then unloads to transfer in an orderly manner to a file. This allows the writes to be asynchronous with the events TaskA anb B is attempting to Log, while still preserving the event order (probably). Another option might be to set up a file descriptor for the file so that you can use select() to pend on multiple events. Take a look at the circular buffer example in the NNDK Prog. Manual (section 16). However, as I'm writing this, it seems to me that even with a file_descriptor/select() approch you only can see that multiple events have occurred, (ie a write request from TaskA, and/or one from TaskB), but not which event came first. Accordingly, the fd/select approach is probably not a great soln.

Your last resort, and one that might be invaluable for testing in any case is to have TaskA and TaskB timestamp their respective data elements (another field in their structs?). Then you can use these stamps to really validate whether writes to the final file are landing in the correct order.

Just a few thoughts... If I had to pick one I'd have TaskA and B post data to an OS_FIFO that TaskC unloads to do sequential writes. But I'd also add the timestamps. If you go that route though, be aware that the NB time utilities, (very unfortunately in my opinion) only increment seconds, not uSecs as on most Linux platforms. If finer resolution is required, you'll need to write it.
Post Reply