On Sat Apr 02, 2011 at 12:58:34 +1300, Valery V. Sedletski wrote:
When an L4 server is started, its main thread goes into the server loop and blocks until a message from a client is received. When a message is received, a server loop calls a dispatch function, which calls functions, specific to RPC opcodes. The problem is that if one of these functions is blocked, the whole server loop is blocked.
In my case, I am implementing an API, which is called by a client program. This API starts a child process, and has an option to block the calling program, until the child is terminated. This API is called DosExecPgm(). So, the client program calls this API, then the API call blocks, and then the child must be executed, and finally, call another API, which is called DosExit(). But when DosExecPgm is called, the server loop is blocked, and it cannot receive a message for calling the next API, DosExit.
I tried to implement API call blocking using a semaphore. DosExecPgm from a parent process is waiting on the semaphore, and DosExit from a child process reset the semaphore.
So, the problem is with server loop blocking. So, I thought to make for DosExecPgm a dedicated server loop. which is blocked, but the main server loop continues to execute. But how to correctly make these server loops? There are many API's which can block, so, what can I do if not to dedicate a separate loop for each function? And, if there are many server loops, then there will be many threads executing them, so I must to register each thread on the name server. -- Then how can the calling program determine, which server thread to call for each API?
I feel that these problems have common solutions, but i'm in trouble -- maybe, someone will help with finding these common solutions?
I think the generic solution is to maintain a couple of worker threads inside the server and delegate work to them, keeping the main server thread responsive. Another solution could be to have a thread per client.
On Mon Apr 04, 2011 at 09:22:07 +1300, Valery V. Sedletski wrote:
On Sat, 02 Apr 2011 12:58:34 +1300 (MSD), Valery V. Sedletski wrote:
Hi all.
...
I have rethought the problem and, it seems, found the solution -- still block on a semaphore, but not in server stub, but in the client routine which calls the RPC to the server.
But the problem remains -- the semaphore is in the server, but need to share it with the client for it to reset it. -- So the next question arises -- how to tell DICE to map the semaphore to the client? -- I have the semaphore in the server, and trying to return it from the RPC to the server. But DICE returns a copy of the semaphore, and not maps it to the client. I try to use the following IDL declaration:
APIRET dos_ExecPgm ([out, string, prealloc_client, prealloc_server] char **pObjname, [in] long cbObjname, [in] unsigned long execFlag, [in, string] char *pArg, [in, string] char *pEnv, [in, out] struct _RESULTCODES *pRes, [out, size_is(len), ref, prealloc_client, prealloc_server] l4semaphore_t **tSem, [out] int *len, [in, string] char *pName);
-- so, I'm trying to use 'ref' attribute for tSem. But in that case, DICE requires me to specify the array with 'len' parameter. Can I avoid this length parameter? (I must return one l4semaphore_t * value from the IDL method, and get the mapping of original semaphore, not its copy).
I think the l4semaphore was never intented to be used between two different tasks. Also, if you would do so, l4semaphore_t must be in shared memory between the two tasks, as the structure is for example maintaining a counter that is used in the up and down implementations. Thus you'd need to map the memory to the task, and have it placed on a separate page. I guess in your situation blocking on a worker thread in server could work.
Adam