<< Back to Writing Codezero Applications
In this section you may find examples on how to create services that serves requests from potential applications using IPC.
In distributed computing, the core methodology involves creation of clients and servers using autogenerated source code stubs. Often, the methodology is complemented by object oriented programming mechanisms such as interfaces and implementations of objects.
In Codezero, client server communication is kept simple and lightweight. There is no mechanism to create autogenerated client and server stubs, as this methodology is known to create notoriously complicated and heavyweight implementations. Instead, any client server communication is created manually.
It is still possible to create stubs and leverage object-oriented programming, but this is not enforced as a methodology.
On a typical Codezero service, request handling pattern involves the code snippet as below.
void handle_requests(void) { /* Generic ipc data */ u32 mr[MR_UNUSED_TOTAL]; l4id_t senderid; struct tcb *sender; u32 tag; int ret; /* Receive request from any thread */ if ((ret = l4_receive(L4_ANYTHREAD)) < 0) goto out_err; /* Read the tag that identifies request */ tag = l4_get_tag(); /* Read the sender id, set by the microkernel */ senderid = l4_get_sender(); /* Retrieve the information stored on the service about the sender */ if (!(sender = find_task(senderid))) { l4_ipc_return(-ESRCH); return; } /* Read message megisters */ for (int i = 0; i < MR_UNUSED_TOTAL; i++) mr[i] = read_mr(MR_UNUSED_START + i); /* Handle request according to the given tag */ switch(tag) { case L4_IPC_REQUEST_NO_RETURN: { ret = handle_no_return_request(sender, (char *)mr[0], mr[1], mr[2]); if (ret < 0) break; /* We only return for errors */ else return; /* Otherwise we don't return, one way request. */ } case L4_IPC_REQUEST_WITH_RETURN: ret = handle_returning_request(sender, (void *)mr[0]); break; default: } /* Send return message back to the client */ if ((ret = l4_ipc_return(ret)) < 0) { printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret); BUG(); } out_err: printf("IPC Error occured: %d\n", err); } void main(void) { /* Initialise service */ initialise(); while (1) { handle_requests(); } }
A note worth mentioning here is that the communication in this example is synchronous. In other words, both the client and the server tasks block during IPC. This may create complications in the cases where one of the parties involved in the IPC are buggy. For example, a service in its return phase may block indefinitely if the client does not adhere to the protocol and issue a receive.
Currently this is the model of communication, but such problems will be solved in the future releases with remedies such as multithreaded servers, for example.