forked from xuos/xiuos
Support multithread server
This commit is contained in:
parent
d05754a98e
commit
3a99cc550c
|
@ -30,7 +30,8 @@ int IPC_DO_SERVE_FUNC(Ipc_hello_string)(char* buf, int* len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
IPC_SERVER_INTERFACE(Ipc_add, 2);
|
||||
// IPC_SERVER_INTERFACE(Ipc_add, 2);
|
||||
IPC_SERVER_THREAD_INTERFACE(Ipc_add, 2);
|
||||
IPC_SERVER_INTERFACE(Ipc_hello_string, 2);
|
||||
IPC_SERVER_REGISTER_INTERFACES(IpcSimpleServer, 2, Ipc_hello_string, Ipc_add);
|
||||
|
||||
|
|
|
@ -23,18 +23,18 @@ int IPC_DO_SERVE_FUNC(Ipc_intr_3)(void* ignore)
|
|||
int IPC_DO_SERVE_FUNC(Ipc_wait_intr_3)(void* ignore)
|
||||
{
|
||||
// delay the this handle
|
||||
if (!has_one_interrupt) {
|
||||
delay_session();
|
||||
return -1;
|
||||
while (!has_one_interrupt) {
|
||||
yield(SYS_TASK_YIELD_NO_REASON);
|
||||
}
|
||||
|
||||
// serve can be done by now
|
||||
has_one_interrupt = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IPC_SERVER_INTERFACE(Ipc_intr_3, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_wait_intr_3, 1);
|
||||
IPC_SERVER_THREAD_INTERFACE(Ipc_wait_intr_3, 1);
|
||||
IPC_SERVER_REGISTER_INTERFACES(IpcSwIntrHandler, 2, Ipc_intr_3, Ipc_wait_intr_3);
|
||||
int main()
|
||||
{
|
||||
|
|
|
@ -168,25 +168,6 @@ int cur_session_id(void)
|
|||
return cur_sess_id;
|
||||
}
|
||||
|
||||
static bool session_delayed = false;
|
||||
void delay_session(void)
|
||||
{
|
||||
session_delayed = true;
|
||||
}
|
||||
|
||||
bool is_cur_session_delayed(void)
|
||||
{
|
||||
return session_delayed;
|
||||
}
|
||||
|
||||
bool is_cur_handler_been_delayed()
|
||||
{
|
||||
if (ipc_server_loop_cur_msg == NULL) {
|
||||
return false;
|
||||
}
|
||||
return ipc_server_loop_cur_msg->header.delayed == 1;
|
||||
}
|
||||
|
||||
void ipc_server_loop(struct IpcNode* ipc_node)
|
||||
{
|
||||
struct Session session_list[NR_MAX_SESSION];
|
||||
|
@ -199,49 +180,82 @@ void ipc_server_loop(struct IpcNode* ipc_node)
|
|||
*/
|
||||
poll_session(session_list, NR_MAX_SESSION);
|
||||
/* handle each session */
|
||||
bool has_delayed = true;
|
||||
for (int repeat = 0; repeat <= 1 && has_delayed; repeat++) {
|
||||
has_delayed = false;
|
||||
for (int i = 0; i < NR_MAX_SESSION; i++) {
|
||||
session_delayed = false;
|
||||
if (session_list[i].buf == NULL) {
|
||||
yield(SYS_TASK_YIELD_NO_REASON);
|
||||
for (int i = 0; i < NR_MAX_SESSION; i++) {
|
||||
if (session_list[i].buf == NULL) {
|
||||
yield(SYS_TASK_YIELD_NO_REASON);
|
||||
break;
|
||||
}
|
||||
cur_sess_id = session_list[i].id;
|
||||
ipc_server_loop_cur_msg = IPCSESSION_MSG(&session_list[i]);
|
||||
if (ipc_server_loop_cur_msg->header.magic == IPC_MSG_MAGIC && ipc_server_loop_cur_msg->header.valid == 1 && //
|
||||
ipc_server_loop_cur_msg->header.done == 1) {
|
||||
session_forward_head(&session_list[i], ipc_server_loop_cur_msg->header.len);
|
||||
ipc_server_loop_cur_msg = IPCSESSION_MSG(&session_list[i]);
|
||||
}
|
||||
/* handle every message in current session
|
||||
a session could be delay in case one of its message(current message) needs to wait for an interrupt message's arrival
|
||||
interfaces[opcode] should explicitly call delay_session() and return to delay this session
|
||||
*/
|
||||
while (ipc_server_loop_cur_msg->header.magic == IPC_MSG_MAGIC && ipc_server_loop_cur_msg->header.valid == 1 && //
|
||||
ipc_server_loop_cur_msg->header.handling == 0 && ipc_server_loop_cur_msg->header.done == 0) {
|
||||
if (session_used_size(&session_list[i]) == 0 && session_forward_tail(&session_list[i], ipc_server_loop_cur_msg->header.len) < 0) {
|
||||
break;
|
||||
}
|
||||
cur_sess_id = session_list[i].id;
|
||||
ipc_server_loop_cur_msg = IPCSESSION_MSG(&session_list[i]);
|
||||
/* handle every message in current session
|
||||
a session could be delay in case one of its message(current message) needs to wait for an interrupt message's arrival
|
||||
interfaces[opcode] should explicitly call delay_session() and return to delay this session
|
||||
*/
|
||||
while (ipc_server_loop_cur_msg->header.magic == IPC_MSG_MAGIC && ipc_server_loop_cur_msg->header.valid == 1 && ipc_server_loop_cur_msg->header.done == 0) {
|
||||
if (session_used_size(&session_list[i]) == 0 && session_forward_tail(&session_list[i], ipc_server_loop_cur_msg->header.len) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// this is a message needs to handle
|
||||
if (ipc_node->interfaces[ipc_server_loop_cur_msg->header.opcode]) {
|
||||
ipc_node->interfaces[ipc_server_loop_cur_msg->header.opcode](ipc_server_loop_cur_msg);
|
||||
// check if this session is delayed by op handler, all messages after the delayed message in current session is blocked.
|
||||
if (ipc_server_loop_cur_msg->header.done == 0) {
|
||||
ipc_server_loop_cur_msg->header.delayed = 1;
|
||||
has_delayed = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("Unsupport opcode(%u) for server: %s\n", ipc_server_loop_cur_msg->header.opcode, ipc_node->name);
|
||||
}
|
||||
// current msg is a message that needs to ignore
|
||||
// finish this message in server's perspective
|
||||
if (session_forward_head(&session_list[i], ipc_server_loop_cur_msg->header.len) < 0) {
|
||||
break;
|
||||
}
|
||||
ipc_server_loop_cur_msg = IPCSESSION_MSG(&session_list[i]);
|
||||
// this is a message needs to handle
|
||||
if (ipc_node->interfaces[ipc_server_loop_cur_msg->header.opcode]) {
|
||||
ipc_node->interfaces[ipc_server_loop_cur_msg->header.opcode](ipc_server_loop_cur_msg);
|
||||
} else {
|
||||
printf("Unsupport opcode(%u) for server: %s\n", ipc_server_loop_cur_msg->header.opcode, ipc_node->name);
|
||||
}
|
||||
// stop handle this session
|
||||
cur_sess_id = -1;
|
||||
ipc_server_loop_cur_msg = NULL;
|
||||
// current msg is a message that needs to ignore
|
||||
// finish this message in server's perspective
|
||||
if (ipc_server_loop_cur_msg->header.done == 0) {
|
||||
break;
|
||||
}
|
||||
session_forward_head(&session_list[i], ipc_server_loop_cur_msg->header.len);
|
||||
ipc_server_loop_cur_msg = IPCSESSION_MSG(&session_list[i]);
|
||||
}
|
||||
// stop handle this session
|
||||
cur_sess_id = -1;
|
||||
ipc_server_loop_cur_msg = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// utils
|
||||
void _ipc_addr_to_buf(uintptr_t addr, char buf[17])
|
||||
{
|
||||
int buf_idx = 0;
|
||||
while (addr != 0) {
|
||||
int x = addr % 16;
|
||||
if (x < 10) {
|
||||
buf[buf_idx] = x + '0';
|
||||
} else {
|
||||
buf[buf_idx] = x - 10 + 'A';
|
||||
}
|
||||
buf_idx++;
|
||||
addr /= 16;
|
||||
}
|
||||
buf[buf_idx] = '\0';
|
||||
}
|
||||
|
||||
uintptr_t _ipc_buf_to_addr(char* buf)
|
||||
{
|
||||
uintptr_t addr = 0;
|
||||
int buf_idx = 0;
|
||||
uintptr_t multiplier = 1;
|
||||
while (buf_idx < 17 && buf[buf_idx] != '\0') {
|
||||
uint8_t x = (uint8_t)buf[buf_idx];
|
||||
if (x >= '0' && x <= '9') {
|
||||
x -= '0';
|
||||
} else if (x >= 'A' && x <= 'F') {
|
||||
x -= 'A';
|
||||
x += 10;
|
||||
}
|
||||
addr += (uintptr_t)x * multiplier;
|
||||
multiplier *= 16;
|
||||
buf_idx++;
|
||||
}
|
||||
return addr;
|
||||
}
|
|
@ -33,6 +33,7 @@ Modification:
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ipcargs.h"
|
||||
#include "session.h"
|
||||
|
@ -47,7 +48,7 @@ typedef struct {
|
|||
uint64_t valid : 1; // for server to peek new msg
|
||||
uint64_t done : 1; // for client to check request done
|
||||
uint64_t init : 1; // for client to check request done
|
||||
uint64_t delayed : 1;
|
||||
uint64_t handling : 1;
|
||||
uint64_t nr_args : 4;
|
||||
uint64_t opcode : 8;
|
||||
uint64_t len : 16;
|
||||
|
@ -191,6 +192,7 @@ void ipc_server_loop(struct IpcNode* ipc_node);
|
|||
#define IPC_CALL(ipc_name) ipc_call_copy_args_##ipc_name
|
||||
|
||||
#define IPC_SERVE(ipc_name) ipc_serve_##ipc_name
|
||||
#define IPC_THREAD_SERVE(ipc_name) ipc_thread_serve_##ipc_name
|
||||
#define IPC_DO_SERVE_FUNC(ipc_name) ipc_do_serve_##ipc_name
|
||||
|
||||
/// when defining a ipc server:
|
||||
|
@ -236,7 +238,6 @@ void ipc_server_loop(struct IpcNode* ipc_node);
|
|||
return res; \
|
||||
}
|
||||
|
||||
bool is_cur_session_delayed(void);
|
||||
#define IPC_SERVER_INTERFACE(ipc_name, argc) \
|
||||
static int IPC_SERVE(ipc_name)(struct IpcMsg * msg) \
|
||||
{ \
|
||||
|
@ -245,16 +246,43 @@ bool is_cur_session_delayed(void);
|
|||
argv[i] = ipc_msg_get_nth_arg_buf(msg, i); \
|
||||
} \
|
||||
int32_t _ret = IPC_DO_SERVE##argc(ipc_name); \
|
||||
if (!is_cur_session_delayed()) { \
|
||||
ipc_msg_set_return(msg, &_ret); \
|
||||
msg->header.done = 1; \
|
||||
} \
|
||||
ipc_msg_set_return(msg, &_ret); \
|
||||
msg->header.done = 1; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
int cur_session_id(void);
|
||||
/// @brief delay the session(message, or a inter-process-call)
|
||||
/// the delayed call will be handled again later from begining, not from the position where delay_session() is called.
|
||||
/// @param
|
||||
void delay_session(void);
|
||||
bool is_cur_handler_been_delayed();
|
||||
void _ipc_addr_to_buf(uintptr_t addr, char buf[17]);
|
||||
uintptr_t _ipc_buf_to_addr(char* buf);
|
||||
|
||||
#define IPC_SERVER_THREAD_INTERFACE(ipc_name, argc) \
|
||||
static int IPC_THREAD_SERVE(ipc_name)(int ipc_argc, char** ipc_argv) \
|
||||
{ \
|
||||
if (ipc_argc != 2) { \
|
||||
printf("[%s] Error server thread creation.\n", __func__); \
|
||||
exit(1); \
|
||||
return -1; \
|
||||
} \
|
||||
struct IpcMsg* msg = (struct IpcMsg*)_ipc_buf_to_addr(ipc_argv[1]); \
|
||||
void* argv[argc]; \
|
||||
for (int i = 0; i < argc; i++) { \
|
||||
argv[i] = ipc_msg_get_nth_arg_buf(msg, i); \
|
||||
} \
|
||||
int32_t _ret = IPC_DO_SERVE##argc(ipc_name); \
|
||||
ipc_msg_set_return(msg, &_ret); \
|
||||
msg->header.done = 1; \
|
||||
exit(0); \
|
||||
return 0; \
|
||||
} \
|
||||
static int IPC_SERVE(ipc_name)(struct IpcMsg * msg) \
|
||||
{ \
|
||||
char addr_buf[17]; \
|
||||
_ipc_addr_to_buf((uintptr_t)msg, addr_buf); \
|
||||
char* param[] = { #ipc_name, addr_buf, NULL }; \
|
||||
int tid = thread(IPC_THREAD_SERVE(ipc_name), #ipc_name, param); \
|
||||
if (tid > 0) { \
|
||||
msg->header.handling = 1; \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
int cur_session_id(void);
|
|
@ -63,15 +63,11 @@ int IPC_DO_SERVE_FUNC(Ipc_sem_wait)(sem_t* sem, int* timeout)
|
|||
|
||||
/// @todo support timeout
|
||||
// return if sem is freed(no valid) or sem count is sufficient
|
||||
if (!sem_pool[*sem].valid || sem_pool[*sem].count > 0) {
|
||||
sem_pool[*sem].count--;
|
||||
return SEMAPHORE_SUC;
|
||||
}
|
||||
while (sem_pool[*sem].valid && sem_pool[*sem].count <= 0)
|
||||
;
|
||||
|
||||
// delay current session
|
||||
// this handler will be invoke again later
|
||||
delay_session();
|
||||
return SEMAPHORE_ERR;
|
||||
sem_pool[*sem].count--;
|
||||
return SEMAPHORE_SUC;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_sem_signal)(sem_t* sem)
|
||||
|
@ -91,7 +87,7 @@ int IPC_DO_SERVE_FUNC(Ipc_sem_signal)(sem_t* sem)
|
|||
IPC_SERVER_INTERFACE(Ipc_sem_create, 2);
|
||||
IPC_SERVER_INTERFACE(Ipc_sem_delete, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_sem_signal, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_sem_wait, 2);
|
||||
IPC_SERVER_THREAD_INTERFACE(Ipc_sem_wait, 2);
|
||||
IPC_SERVER_REGISTER_INTERFACES(IpcSemaphoreServer, 4, //
|
||||
Ipc_sem_create, Ipc_sem_delete, Ipc_sem_signal, Ipc_sem_wait);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct {
|
|||
uint64_t valid : 1; // for server to peek new msg
|
||||
uint64_t done : 1; // for client to check request done
|
||||
uint64_t init : 1; // for client to check request done
|
||||
uint64_t delayed : 1;
|
||||
uint64_t handling : 1;
|
||||
uint64_t nr_args : 4;
|
||||
uint64_t opcode : 8;
|
||||
uint64_t len : 16;
|
||||
|
|
|
@ -39,7 +39,7 @@ Modification:
|
|||
static inline bool is_msg_needed(struct IpcMsg* msg)
|
||||
{
|
||||
assert(msg != NULL);
|
||||
return msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0 && msg->header.delayed == 0;
|
||||
return msg->header.magic == IPC_MSG_MAGIC && msg->header.valid == 1 && msg->header.done == 0 && msg->header.handling == 0;
|
||||
}
|
||||
|
||||
int sys_poll_session(struct Session* userland_session_arr, int arr_capacity)
|
||||
|
|
|
@ -166,6 +166,10 @@ static void _dealloc_task_cb(struct Thread* task)
|
|||
bitmap64_free(&task->memspace->thread_stack_idx_bitmap, task->thread_context.user_stack_idx);
|
||||
/* thread's user stack space is also allocated for kernel free space */
|
||||
assert(kfree((char*)task->thread_context.ustack_kvaddr));
|
||||
|
||||
if (task->memspace != NULL) {
|
||||
task->memspace->mem_size -= USER_STACK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* free thread's kernel stack */
|
||||
|
|
Loading…
Reference in New Issue