How to block an API call without blocking server message loop?
adam at os.inf.tu-dresden.de
Mon Apr 4 20:23:43 CEST 2011
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
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_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_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 adam at os.inf.tu-dresden.de
More information about the l4-hackers