33 | | Simple RPC requests are blocking for the client thread: the client thread register its request in the target RPC_FIFO, blocks on the THREAD_BLOCKED_RPC condition, and deschedules. The client thread is unblocked by the RPC server thread, when the RPC is completed. |
| 32 | ALMOS-MKH supports two modes for an RPC request : |
| 33 | * '''simple RPC''' : the client thread send the RPC request to one single server, and is expecting one single response. |
| 34 | * '''parallel RPC''' : the client thread send in parallel several RPC requests to several servers, and is expecting several responses. |
| 35 | |
| 36 | Both RPC types use the same RPC descriptor format. One entry in the RPC_FIFO (located on the server side) contains a remote pointer (xptr_t) on the RPC descriptor (''rpc_desc_t''), that is stored on the client side. This RPC descriptor contains the following informations: |
| 37 | * The '''index''' field defines the required service type (ALMOS-MKH defines about 30 service types). |
| 38 | * The '''blocked''' field defines the RPC mode : true for a simple RPC, false for a parallel RPC. |
| 39 | * The '''args''' field is an array of 10 uint64_t, containing the service arguments (both input & output). |
| 40 | * The '''thread''' field is a local pointer on the client thread (used by the server thread to unblock the client thread). |
| 41 | * The '''lid''' field defines the client core local index (used by the server thread to send the completion IPI). |
| 42 | * The '''rsp''' field is a local pointer on an expected responses counter on the client side (can be larger than one for a parallel RPC). |
| 43 | |
| 44 | The semantic of the '''args''' array depends on the service type, as defined by the '''index''' field. |
| 45 | |
| 46 | This format supports both simple and parallel RPCs: The client thread initializes the '''responses''' counter with the number of expected responses, and each server thread atomically decrement this counter when the RPC request has been satisfied. |
| 47 | |
| 48 | == 4) Simple RPC scenario == |
| 49 | |
| 50 | Simple RPC requests are blocking for the client thread. The client thread must perform the following tasks: |
| 51 | 1. allocate memory in the client cluster for the RPC descriptor (can be in the client stack), |
| 52 | 1. allocate in the client cluster an expected response counter (can be in the client stack), |
| 53 | 1. initialize this RPC descriptor (this includes RPC arguments marshaling), as well as the responses counter (one expected response), |
| 54 | 1. register the extended pointer on the RPC descriptor in the server FIFO, |
| 55 | 1. send an IPI to the selected core in the server cluster, |
| 56 | 1. blocks and deschedule, waiting to be re-activated by the server thread when the server completed the requested service. |
| 57 | |
| 58 | For each RPC service type XYZ, ALMOS-MKH define a specific ''rpc_xyz_client()'' function that performs the 3 first tasks, and call the generic ''rpc_send()'' function to perform the three last tasks. |
| 59 | |
| 60 | On the server side, a kernel RPC thread is activated at the next scheduling point on the selected server core, as soon as the RPC_FIFO is non-empty. This server thread executes the following tasks: |
| 61 | 1. extract relevant informations from RPC descriptor stored in client cluster, |
| 62 | 1. depending on the RPC index, call the specific ''roc_xyz_server()'' function to perform the RPC arguments unmarshmaling, |
| 63 | 1. call the recant kernel function to and execute the requested service, |
| 64 | 1. atomically increment the responses counter in the client cluster, |
| 65 | 1. if this response is the last expected response, unblocks the client thread, and send an IPI to the client core. |
39 | | == 4) Parallel RPC requests handling == |
| 71 | All RPC services defined by ALMOS-MKH can be used in ''simple'' or ''parallel'' mode. |
| 72 | Only the behavior of the client has to be modified for a parallel RPC : To send parallel RPC requests to several servers, the client thread doe not block until the last request has been registered in the last server FIFO. |
| 73 | Therefore, to request a RPC service XYZ in parallel mode to N servers, the client function does NOT use the ''rpc_xyz_client()'' function, and follows the following the client scenario: |
| 74 | 1. allocate itself an array of RPC descriptors rpc[N] in client cluster (one per target server), |
| 75 | 1. allocate itself a shared responses counter in client cluster (can be in client stack), |
| 76 | 1. initialize itself the N RPC descriptors, as well as the responses counter (N expected responses), |
| 77 | 1. for all servers, register an extended pointer on rpc[i] in the server[i] FIFO, |
| 78 | 1. for all servers, send an IPI to the selected core in the server[i] cluster, |
| 79 | 1. blocks and deschedule, waiting to be re-activated by the last server thread when it completed the requested service. |
43 | | At any time, only one RPC thread has the FIFO ownership and can consume RPC requests from the FIFO. Nevertheless, ALMOS-MKH supports supports several RPC server threads per RPC_FIFO because a given RPC thread T handling a given request can block, waiting for a shared resource, such as a peripheral. In that case, the blocked RPC thread T releases the FIFO ownership before blocking and descheduling. This RPC thread T will complete the current RPC request when the blocking condition is solved, and the thread T is rescheduled. If the RPC FIFO is not empty, another RPC thread T' will be scheduled to handle the pending RPC requests. If all existing RPC threads are blocked, a new RPC thread is dynamically created. |
| 83 | == 6) Pool of RPC servers == |
| 84 | |
| 85 | In order to avoid deadlocks, for each core, ALMOS-MKH defines a private pool of RPC threads associated to one single RPC_FIFO[i,k]. |
| 86 | If a given RPC thread extracted request[i] from the FIFO, but is blocked, waiting for a shared resource, the next request[i+i] in the FIFO can be extracted and handled by another RPC thread. In that case, the blocked RPC thread T releases the FIFO ownership before blocking and descheduling. This RPC thread T will complete the current RPC request when the blocking condition is solved, and the thread T is rescheduled. If the RPC FIFO is not empty, another RPC thread T' will be scheduled to handle the pending RPC requests. If all existing RPC threads are blocked, a new RPC thread is dynamically created. |
| 87 | |
| 88 | At any time, only one RPC thread has the FIFO ownership and can consume RPC requests from the FIFO. |
48 | | == 5) RPC request format == |
49 | | |
50 | | ALMOS-MKH implement two types of RPCs : |
51 | | * '''simple RPC''' : the client thread send the RPC request to one single server waiting one single response. |
52 | | * '''multicast RPC''' : the client thread send the same RPC request to several servers, expecting several responses. |
53 | | |
54 | | Each entry in the RPC_FIFO contains a remote pointer (xptr_t) on a RPC descriptor (''rpc_desc_t''), that is stored on the client side (in the client thread stack). This RPC descriptor has a fixed format, and contains the following informations: |
55 | | * The '''index''' field defines the required service type. |
56 | | * The '''args''' field is an array of 10 uint64_t, containing the service arguments (both input & output). |
57 | | * The '''thread''' field defines the client thread (used by the server thread to unblock the client thread). |
58 | | * The '''lid''' field defines the client core local index (used by the server thread to send the completion IPI). |
59 | | * The '''response''' field defines the number of expected responses. |
60 | | |
61 | | The semantic of the '''args''' array depends on the RPC '''index''' field. |
62 | | |
63 | | This format supports both simple and multicast RPCs: The client thread initializes the '''response''' field with the number of expected responses, and each server thread atomically decrement this counter when the RPC request has been satisfied. |
64 | | |
65 | | == 6) How to define a new RPC == |
| 93 | == 7) How to define a new RPC == |