From 1405a1e48a289db5793e0a9c4098787098f71d4d Mon Sep 17 00:00:00 2001 From: hzc1998 <2323168280@qq.com> Date: Sun, 30 Oct 2022 19:29:39 +0800 Subject: [PATCH] feat: add ipc 1. add anonymous shm 2. add ipc and ipc syscall --- src/include/base/exobj.h | 2 + src/include/base/ipc.h | 84 +++++++ src/include/base/sched.h | 2 +- src/include/base/sharemem.h | 8 + src/include/base/thread.h | 20 +- src/ipc/ipc.c | 175 ++++++++++++++ src/mm/sharemem.c | 165 +++++++++----- src/mm/vmspace.c | 2 +- src/process/process.c | 10 +- src/process/syscall.c | 443 +++++++++++++++++++++++++++++++++++- src/sched/sched.c | 16 +- src/sched/thread.c | 22 +- 12 files changed, 870 insertions(+), 79 deletions(-) create mode 100644 src/include/base/ipc.h create mode 100644 src/ipc/ipc.c diff --git a/src/include/base/exobj.h b/src/include/base/exobj.h index 68ac44b..d0e9a7e 100644 --- a/src/include/base/exobj.h +++ b/src/include/base/exobj.h @@ -39,6 +39,8 @@ typedef enum NX_ExposedObjectType NX_EXOBJ_SHMADDR, NX_EXOBJ_FILE, NX_EXOBJ_DIR, + NX_EXOBJ_IPC, + NX_EXOBJ_IPC_CHANNEL, NX_EXOBJ_TYPE_NR, } NX_ExposedObjectType; diff --git a/src/include/base/ipc.h b/src/include/base/ipc.h new file mode 100644 index 0000000..4a5b814 --- /dev/null +++ b/src/include/base/ipc.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2018-2022, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: IPC + * + * Change Logs: + * Date Author Notes + * 2022-11-02 JasonHu Init + */ + +#ifndef __IPC_H__ +#define __IPC_H__ + +#include +#include +#include +#include + +#define NX_IPC_NAME_LEN 32 +#define NX_IPC_CHANNEL_MAX 65535 + +#define NX_IPC_THREAD_STACK_SIZE 8192 +#define NX_IPC_HELPER_NAME "IpcHelper" + +typedef enum +{ + NX_IPC_CHANNEL_INIT = 0, + NX_IPC_CHANNEL_ACTIVE, + NX_IPC_CHANNEL_DEACTIVE, + NX_IPC_CHANNEL_CLOSE, +} NX_IpcChannelState; + +typedef struct NX_IpcServer +{ + NX_List list; + void * handler; + NX_Size maxClient; + NX_List clientList; /* list for client */ + NX_Spin lock; /* lock for client list */ + void * thread; /* thread for ipc server */ + void * process; /* process for ipc server */ + NX_Atomic channelCount; + char name[NX_IPC_NAME_LEN]; +} NX_IpcServer; + +typedef struct +{ + NX_Addr clientBufAddr; + NX_Addr serverBufAddr; + NX_Size size; +} NX_IpcSharedBuf; + +typedef struct NX_IpcChannel +{ + NX_List list; /* list for all channel */ + NX_Size returnValue; + void * serverThread; /* server thread */ + void * clientThread; /* client thread */ + void * shm; + void * handler; /* user handler */ + NX_IpcServer * ipc; + NX_IpcChannelState state; + NX_IpcSharedBuf buf; +} NX_IpcChannel; + +typedef struct +{ + NX_Addr bufAddr; + NX_Size bufSize; +} NX_IpcClientConfig; + +NX_IpcServer * NX_IpcSearch(const char * name); + +NX_IpcServer * NX_IpcCreateServer(const char * name, + void * serverHandler, NX_Size maxClient); +NX_Error NX_IpcDestroyServer(NX_IpcServer * ipc); + +NX_IpcChannel * NX_IpcCreateChannel(NX_IpcServer * ipc, + NX_Addr serverBufAddr, NX_Addr clientBufAddr, NX_Size bufSize); +NX_Error NX_IpcDestroyChannel(NX_IpcChannel * channel); +NX_Error NX_IpcExitServer(NX_IpcServer * ipc); + +#endif /* __IPC_H__ */ diff --git a/src/include/base/sched.h b/src/include/base/sched.h index 02ca790..843e895 100644 --- a/src/include/base/sched.h +++ b/src/include/base/sched.h @@ -21,7 +21,7 @@ void NX_SchedToFirstThread(void); void NX_SchedInterruptDisabled(NX_UArch irqLevel); -void NX_SchedLockedIRQ(NX_UArch irqLevel, NX_Spin *lock); +void NX_SchedLockedIRQ(NX_UArch irqLevel, NX_Spin *lock, void * nextThread); void NX_SchedYield(void); void NX_ReSchedCheck(void); void NX_SchedExit(void); diff --git a/src/include/base/sharemem.h b/src/include/base/sharemem.h index 67d359b..36f537d 100644 --- a/src/include/base/sharemem.h +++ b/src/include/base/sharemem.h @@ -15,11 +15,13 @@ #include #include #include +#include #define NX_SHAREMEM_MAX_SIZE (16 * NX_MB) #define NX_SHAREMEM_NAME_LEN 32 #define NX_SHAREMEM_CREATE_NEW 0x01 /* create share memory new */ +#define NX_SHAREMEM_ANONYMOUS 0x02 /* create share memory anonymous */ typedef struct NX_ShareMem { @@ -27,13 +29,19 @@ typedef struct NX_ShareMem NX_Addr pageAddr; NX_Size size; /* share memory size */ NX_Atomic reference; /* share memory map referents */ + NX_U32 flags; char name[NX_SHAREMEM_NAME_LEN]; } NX_ShareMem; +NX_ShareMem * NX_ShareMemoryCreate(const char * name, NX_Size size, NX_U32 flags); + NX_ShareMem * NX_ShareMemOpen(const char * name, NX_Size size, NX_U32 flags); NX_Error NX_ShareMemClose(NX_ShareMem * shm); NX_Error NX_ShareMemMap(NX_ShareMem * shm, void ** outMapAddr); NX_Error NX_ShareMemUnmap(void * addr); +NX_Error NX_ShareMemMapToVmspace(NX_ShareMem * shm, NX_Vmspace * space, void ** outMapAddr); +NX_Error NX_ShareMemUnmapFromVmspace(NX_ShareMem * shm, NX_Vmspace * space, void * vaddr); + #endif /* __MM_SHAREMEM_H__ */ diff --git a/src/include/base/thread.h b/src/include/base/thread.h index 881fadb..4633f64 100644 --- a/src/include/base/thread.h +++ b/src/include/base/thread.h @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef CONFIG_NX_THREAD_NAME_LEN #define NX_THREAD_NAME_LEN CONFIG_NX_THREAD_NAME_LEN @@ -82,7 +83,9 @@ struct NX_ThreadResource NX_Semaphore waiterSem; /* The semaphore of the thread waiting for this thread to exit */ void * tls; /* thread local storage */ NX_SignalTable signals; - + NX_IpcServer * ipcServer; + NX_IpcChannel * ipcChannel; + NX_Mutex * lockStack[NX_THREAD_LOCK_CHAINS_NR]; /* lock stack */ NX_Atomic lockStackTop; /* lock stack top */ }; @@ -114,6 +117,7 @@ struct NX_Thread NX_U8 *stack; /* stack top */ NX_U8 *userStackBase; /* user thread stack base */ NX_Size userStackSize; /* user thread stack size */ + void * userArg; /* thread sched */ NX_U32 timeslice; @@ -144,6 +148,8 @@ struct NX_ThreadManager }; typedef struct NX_ThreadManager NX_ThreadManager; +NX_IMPORT NX_ThreadManager gThreadManagerObject; + typedef NX_Error (* NX_ThreadWalkHandler)(NX_Thread * thread, void * arg); typedef struct @@ -209,4 +215,16 @@ void NX_ThreadUnreadyRun(NX_Thread *thread); void NX_ThreadExitProcess(NX_Thread *thread, NX_Process *process); +NX_INLINE void NX_ThreadEnququeGlobalListUnlocked(NX_Thread *thread) +{ + NX_ListAdd(&thread->globalList, &gThreadManagerObject.globalList); + NX_AtomicInc(&gThreadManagerObject.activeThreadCount); +} + +NX_INLINE void NX_ThreadDeququeGlobalListUnlocked(NX_Thread *thread) +{ + NX_ListDel(&thread->globalList); + NX_AtomicDec(&gThreadManagerObject.activeThreadCount); +} + #endif /* __SCHED_THREAD__ */ diff --git a/src/ipc/ipc.c b/src/ipc/ipc.c new file mode 100644 index 0000000..8903a44 --- /dev/null +++ b/src/ipc/ipc.c @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2018-2022, NXOS Development Team + * SPDX-License-Identifier: Apache-2.0 + * + * Contains: ipc + * + * Change Logs: + * Date Author Notes + * 2022-11-04 JasonHu Init + */ + +#include +#include +#include +#define NX_LOG_NAME "ipc" +#include +#include +#include +#include +#include + +NX_PRIVATE NX_LIST_HEAD(ipcListHead); +NX_PRIVATE NX_SPIN_DEFINE_UNLOCKED(ipcListLock); + +NX_IpcServer * NX_IpcSearch(const char * name) +{ + NX_IpcServer * ipc = NX_NULL, * tmp; + NX_UArch level; + + NX_SpinLockIRQ(&ipcListLock, &level); + NX_ListForEachEntry (tmp, &ipcListHead, list) + { + if (!NX_StrCmp(name, tmp->name)) + { + ipc = tmp; + break; + } + } + NX_SpinUnlockIRQ(&ipcListLock, level); + return ipc; +} + +NX_IpcServer * NX_IpcCreateServer(const char * name, + void * serverHandler, NX_Size maxClient) +{ + NX_IpcServer * ipc; + NX_UArch level; + + ipc = NX_MemAlloc(sizeof(NX_IpcServer)); + if (!ipc) + { + return NX_NULL; + } + + NX_StrCopy(ipc->name, name); + ipc->handler = serverHandler; + ipc->maxClient = maxClient; + ipc->thread = NX_NULL; + ipc->process = NX_NULL; + NX_ListInit(&ipc->clientList); + NX_SpinInit(&ipc->lock); + NX_AtomicSet(&ipc->channelCount, 0); + + NX_SpinLockIRQ(&ipcListLock, &level); + NX_ListAdd(&ipc->list, &ipcListHead); + NX_SpinUnlockIRQ(&ipcListLock, level); + + return ipc; +} + +NX_Error NX_IpcExitServer(NX_IpcServer * ipc) +{ + NX_UArch level; + NX_IpcChannel * channel, * next; + NX_Thread * thread; + + if (!ipc) + { + return NX_EINVAL; + } + + /* send signal to all client thread */ + NX_SpinLockIRQ(&ipc->lock, &level); + NX_ListForEachEntrySafe (channel, next, &ipc->clientList, list) + { + thread = channel->clientThread; + NX_ASSERT(thread); + NX_SignalSend(thread->tid, NX_SIGNAL_KILL, NX_NULL, NX_NULL); + } + NX_SpinUnlockIRQ(&ipc->lock, level); + + /* wait all channel exit */ + while (NX_AtomicGet(&ipc->channelCount) > 0) + { + NX_ThreadSleep(100); + } + return NX_EOK; +} + +NX_Error NX_IpcDestroyServer(NX_IpcServer * ipc) +{ + NX_UArch level; + + if (!ipc) + { + return NX_EINVAL; + } + + NX_SpinLockIRQ(&ipcListLock, &level); + NX_ListDel(&ipc->list); + NX_SpinUnlockIRQ(&ipcListLock, level); + + NX_MemFree(ipc); + + return NX_EOK; +} + +NX_IpcChannel * NX_IpcCreateChannel(NX_IpcServer * ipc, + NX_Addr serverBufAddr, NX_Addr clientBufAddr, NX_Size bufSize) +{ + NX_UArch flags; + NX_IpcChannel * channel; + + channel = NX_MemAlloc(sizeof(NX_IpcChannel)); + if (!channel) + { + return NX_NULL; + } + + /* init channel */ + NX_ListInit(&channel->list); + channel->serverThread = NX_NULL; + channel->clientThread = NX_NULL; + channel->shm = NX_NULL; + channel->handler = NX_NULL; + channel->returnValue = 0; + channel->handler = ipc->handler; + channel->buf.clientBufAddr = clientBufAddr; + channel->buf.serverBufAddr = serverBufAddr; + channel->buf.size = bufSize; + channel->ipc = ipc; + channel->state = NX_IPC_CHANNEL_INIT; + + /* add channel to ipc */ + NX_SpinLockIRQ(&ipc->lock, &flags); + NX_ListAdd(&channel->list, &ipc->clientList); + NX_SpinUnlockIRQ(&ipc->lock, flags); + + return channel; +} + +NX_Error NX_IpcDestroyChannel(NX_IpcChannel * channel) +{ + NX_UArch flags; + + if (!channel) + { + return NX_EINVAL; + } + + /* def channel from ipc */ + NX_SpinLockIRQ(&channel->ipc->lock, &flags); + NX_ListDel(&channel->list); + NX_SpinUnlockIRQ(&channel->ipc->lock, flags); + + channel->ipc = NX_NULL; + channel->shm = NX_NULL; + channel->clientThread = NX_NULL; + channel->serverThread = NX_NULL; + channel->handler = NX_NULL; + + NX_MemFree(channel); + + return NX_EOK; +} diff --git a/src/mm/sharemem.c b/src/mm/sharemem.c index 15a1a44..b762e24 100644 --- a/src/mm/sharemem.c +++ b/src/mm/sharemem.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #define NX_LOG_NAME "shm" #include @@ -57,30 +56,16 @@ NX_PRIVATE NX_ShareMem * NX_ShareMemSearchByAddr(NX_Addr paddr) return NX_NULL; } -NX_ShareMem * NX_ShareMemOpen(const char * name, NX_Size size, NX_U32 flags) +NX_ShareMem * NX_ShareMemoryCreate(const char * name, NX_Size size, NX_U32 flags) { NX_Size pageCount; NX_ShareMem * shm; - if (!name || !size || size > NX_SHAREMEM_MAX_SIZE) + if (!size || (!name && !(flags & NX_SHAREMEM_ANONYMOUS))) { return NX_NULL; } - if ((shm = NX_ShareMemSearchByName(name)) != NX_NULL) /* share memory exist */ - { - if (flags & NX_SHAREMEM_CREATE_NEW) /* share memory must not exist */ - { - return NX_NULL; - } - if (size > shm->size) - { - return NX_NULL; - } - NX_AtomicInc(&shm->reference); - return shm; /* return share mem */ - } - pageCount = NX_DIV_ROUND_UP(size, NX_PAGE_SIZE); shm = NX_MemAlloc(sizeof(NX_ShareMem)); @@ -95,15 +80,67 @@ NX_ShareMem * NX_ShareMemOpen(const char * name, NX_Size size, NX_U32 flags) NX_MemFree(shm); return NX_NULL; } + + if (flags & NX_SHAREMEM_ANONYMOUS) /* anonymous shm */ + { + NX_StrCopyN(shm->name, ".anonymous", NX_SHAREMEM_NAME_LEN); + } + else + { + NX_StrCopyN(shm->name, name, NX_SHAREMEM_NAME_LEN); + } - NX_StrCopyN(shm->name, name, NX_SHAREMEM_NAME_LEN); shm->size = pageCount * NX_PAGE_SIZE; NX_AtomicSet(&shm->reference, 1); + shm->flags = flags & ~NX_SHAREMEM_CREATE_NEW; - NX_UArch level; - NX_SpinLockIRQ(&shareMemLock, &level); - NX_ListAdd(&shm->list, &shareMemListHead); - NX_SpinUnlockIRQ(&shareMemLock, level); + return shm; +} + +NX_ShareMem * NX_ShareMemOpen(const char * name, NX_Size size, NX_U32 flags) +{ + NX_ShareMem * shm; + + if (!size || size > NX_SHAREMEM_MAX_SIZE) + { + return NX_NULL; + } + + if (!(flags & NX_SHAREMEM_ANONYMOUS)) + { + if (!name) + { + return NX_NULL; + } + + if ((shm = NX_ShareMemSearchByName(name)) != NX_NULL) /* share memory exist */ + { + if (flags & NX_SHAREMEM_CREATE_NEW) /* share memory must not exist */ + { + return NX_NULL; + } + if (size > shm->size) + { + return NX_NULL; + } + NX_AtomicInc(&shm->reference); + return shm; /* return share mem */ + } + } + + shm = NX_ShareMemoryCreate(name, size, flags); + if (!shm) + { + return NX_NULL; + } + + if (!(flags & NX_SHAREMEM_ANONYMOUS)) + { + NX_UArch level; + NX_SpinLockIRQ(&shareMemLock, &level); + NX_ListAdd(&shm->list, &shareMemListHead); + NX_SpinUnlockIRQ(&shareMemLock, level); + } return shm; } @@ -127,25 +164,27 @@ NX_Error NX_ShareMemClose(NX_ShareMem * shm) return NX_EOK; } - NX_UArch level; - NX_SpinLockIRQ(&shareMemLock, &level); - NX_ListDel(&shm->list); - NX_SpinUnlockIRQ(&shareMemLock, level); + if (!(shm->flags & NX_SHAREMEM_ANONYMOUS)) + { + NX_UArch level; + NX_SpinLockIRQ(&shareMemLock, &level); + NX_ListDel(&shm->list); + NX_SpinUnlockIRQ(&shareMemLock, level); + } NX_PageFree((void *)shm->pageAddr); shm->pageAddr = 0; + shm->flags = 0; NX_MemFree(shm); return NX_EOK; } -NX_Error NX_ShareMemMap(NX_ShareMem * shm, void ** outMapAddr) +NX_Error NX_ShareMemMapToVmspace(NX_ShareMem * shm, NX_Vmspace * space, void ** outMapAddr) { - NX_Thread * self; - NX_Process * process; void * mapAddr = NX_NULL; NX_Error err; - if (!shm) + if (!shm || !space) { return NX_EINVAL; } @@ -155,6 +194,26 @@ NX_Error NX_ShareMemMap(NX_ShareMem * shm, void ** outMapAddr) return NX_EPERM; } + if ((err = NX_VmspaceMapWithPhy(space, 0, shm->pageAddr, shm->size, NX_PAGE_ATTR_USER, NX_VMSPACE_SHAREMEM, &mapAddr)) != NX_EOK) + { + return err; + } + + NX_AtomicInc(&shm->reference); + + if (outMapAddr) + { + *outMapAddr = mapAddr; + } + + return NX_EOK; +} + +NX_Error NX_ShareMemMap(NX_ShareMem * shm, void ** outMapAddr) +{ + NX_Thread * self; + NX_Process * process; + self = NX_ThreadSelf(); process = NX_ThreadGetProcess(self); @@ -163,19 +222,36 @@ NX_Error NX_ShareMemMap(NX_ShareMem * shm, void ** outMapAddr) return NX_EPERM; } - if ((err = NX_VmspaceMapWithPhy(&process->vmspace, 0, shm->pageAddr, shm->size, NX_PAGE_ATTR_USER, NX_VMSPACE_SHAREMEM, &mapAddr)) != NX_EOK) + return NX_ShareMemMapToVmspace(shm, &process->vmspace, outMapAddr); +} + +NX_Error NX_ShareMemUnmapFromVmspace(NX_ShareMem * shm, NX_Vmspace * space, void * vaddr) +{ + NX_Error err = NX_EOK; + + if (!vaddr || !shm || !space) { - return err; + return NX_EINVAL; } - NX_AtomicInc(&shm->reference); + /* vaddr must page aligned */ + NX_ASSERT(!((NX_Addr)vaddr & NX_PAGE_MASK)); - if (outMapAddr) + /* unmap space */ + if (NX_VmspaceUnmap(space, (NX_Addr)vaddr, shm->size, NX_VMSPACE_SHAREMEM) != NX_EOK) { - *outMapAddr = mapAddr; + return NX_EFAULT; } - return NX_EOK; + NX_ASSERT(NX_AtomicGet(&shm->reference) > 0); + + NX_AtomicDec(&shm->reference); + + if (NX_AtomicGet(&shm->reference) == 0) /* destroy share memory */ + { + err = NX_ShareMemClose(shm); + } + return err; } NX_Error NX_ShareMemUnmap(void * addr) @@ -184,7 +260,6 @@ NX_Error NX_ShareMemUnmap(void * addr) NX_Addr vaddr; NX_Thread * self; NX_Process * process; - NX_Error err = NX_EOK; if (!addr) { @@ -209,19 +284,5 @@ NX_Error NX_ShareMemUnmap(void * addr) return NX_ENOSRCH; } - /* unmap space */ - if (NX_VmspaceUnmap(&process->vmspace, vaddr, shm->size, NX_VMSPACE_SHAREMEM) != NX_EOK) - { - return NX_EFAULT; - } - - NX_ASSERT(NX_AtomicGet(&shm->reference) > 0); - - NX_AtomicDec(&shm->reference); - - if (NX_AtomicGet(&shm->reference) == 0) /* destroy share memory */ - { - err = NX_ShareMemClose(shm); - } - return err; + return NX_ShareMemUnmapFromVmspace(shm, &process->vmspace, (void *)vaddr); } diff --git a/src/mm/vmspace.c b/src/mm/vmspace.c index 8cdae73..d838152 100644 --- a/src/mm/vmspace.c +++ b/src/mm/vmspace.c @@ -612,7 +612,7 @@ NX_Error NX_VmspaceUnmap(NX_Vmspace *space, NX_Addr addr, NX_Size size, NX_U32 f /* addr must page aligned and in space */ if ((addr & NX_PAGE_MASK) || (addr < space->spaceBase) || (addr >= space->spaceTop) || (addr + size) > space->spaceTop) { - NX_LOG_E("unmap: addr %p and size %p error on addr !", addr, size); + NX_LOG_E("unmap: addr %p and size %p error in space [%p-%p] !", addr, size, space->spaceBase, space->spaceTop); return NX_EINVAL; } diff --git a/src/process/process.c b/src/process/process.c index 9a7a83c..5fb803a 100644 --- a/src/process/process.c +++ b/src/process/process.c @@ -922,6 +922,12 @@ void NX_ThreadExitProcess(NX_Thread *thread, NX_Process *process) /* main thread need signal other threads in process */ if (thread->tid == process->pid) { + /* exit ipc server if main thread exist */ + if (thread->resource.ipcServer) + { + NX_IpcExitServer(thread->resource.ipcServer); + } + ProcessExitSignal(process, thread); } @@ -951,7 +957,6 @@ void NX_ThreadExitProcess(NX_Thread *thread, NX_Process *process) thread->resource.process = process; ProcessExitNotify(process); - /* exit exposed table when final thread exit */ NX_ExposedObjectTableExit(&process->exobjTable); } @@ -1045,6 +1050,7 @@ void NX_UserThreadEntry(void * arg) NX_PANIC("user thread handler null!"); } - NX_ProcessExecuteUserThread((void *)self->userHandler, (void *)userStackTop, (void *)(self->stackBase + self->stackSize), arg); + NX_ProcessExecuteUserThread((void *)self->userHandler, (void *)userStackTop, + (void *)(self->stackBase + self->stackSize), self->userArg); NX_PANIC("user thread exit!"); } diff --git a/src/process/syscall.c b/src/process/syscall.c index dac38e9..4deab1b 100644 --- a/src/process/syscall.c +++ b/src/process/syscall.c @@ -11,6 +11,7 @@ #include #include +#define NX_LOG_LEVEL NX_LOG_INFO #define NX_LOG_NAME "syscall" #include #include @@ -29,13 +30,17 @@ #include #include #include +#include +#include +#include +#include #include "process_impl.h" NX_PRIVATE int SysInvalidCall(void) { - NX_Thread *cur = NX_ThreadSelf(); - NX_LOG_E("thread %s/%d call invalid syscall!", cur->name, cur->tid); + //NX_Thread *cur = NX_ThreadSelf(); + //NX_LOG_E("thread %s/%d call invalid syscall!", cur->name, cur->tid); return 0; } @@ -691,7 +696,7 @@ NX_PRIVATE NX_Error SysThreadCreate(NX_ThreadAttr * attr, NX_ThreadHandler handl NX_ASSERT(stackBase); /* create thread */ - thread = NX_ThreadCreate("uthread", NX_UserThreadEntry, arg, threadAttr.schedPriority); + thread = NX_ThreadCreate("uthread", NX_UserThreadEntry, NX_NULL, threadAttr.schedPriority); if (thread == NX_NULL) { NX_LOG_E("create thread error!"); @@ -702,6 +707,7 @@ NX_PRIVATE NX_Error SysThreadCreate(NX_ThreadAttr * attr, NX_ThreadHandler handl thread->userHandler = handler; thread->userStackSize = threadAttr.stackSize; thread->userStackBase = stackBase; + thread->userArg = arg; /* map tls */ if (NX_ProcessMapTls(process, thread) != NX_EOK) @@ -1990,7 +1996,7 @@ out: return err; } -NX_PRIVATE NX_Error ShmCloseSolt(void * object, NX_ExposedObjectType type) +NX_Error ShmCloseSolt(void * object, NX_ExposedObjectType type) { NX_ShareMem * shm; @@ -2095,6 +2101,431 @@ NX_Error SysShareMemMap(NX_Solt shmSolt, void ** outMapAddr, NX_Solt * outSolt) return err; } +NX_PRIVATE NX_Error IpcCreateHelperThread(NX_Thread * server, NX_IpcChannel * channel, + void * handler, void * arg) +{ + NX_Thread * thread; + NX_Thread * client; + NX_Process * process; + NX_Error err; + void * stackBase = NX_NULL; + char name[32]; + + client = channel->clientThread; + + NX_SNPrintf(name, 32, NX_IPC_HELPER_NAME "/%d", client->tid); + + thread = NX_ThreadCreate(name, NX_UserThreadEntry, NX_NULL, server->priority); + if (!thread) + { + NX_LOG_E("create ipc server thread failed!"); + return NX_EINVAL; + } + + process = NX_ThreadGetProcess(server); + NX_ASSERT(process); + + /* map stack */ + err = NX_VmspaceMap(&process->vmspace, 0, NX_IPC_THREAD_STACK_SIZE, NX_PAGE_ATTR_USER, 0, &stackBase); + if (err != NX_EOK) + { + NX_LOG_E("map user stack error!"); + return err; + } + NX_ASSERT(stackBase); + + /* set user info */ + thread->userHandler = handler; + thread->userStackSize = NX_IPC_THREAD_STACK_SIZE; + thread->userStackBase = stackBase; + thread->userArg = arg; + + /* map tls */ + if (NX_ProcessMapTls(process, thread) != NX_EOK) + { + NX_LOG_E("map thread tls error!"); + NX_ThreadDestroy(thread); + NX_VmspaceUnmap(&process->vmspace, (NX_Addr)stackBase, NX_IPC_THREAD_STACK_SIZE, 0); + return NX_ENOMEM; + } + + /* add thread to system */ + NX_ProcessAppendThread(process, thread); + NX_ThreadEnququeGlobalListUnlocked(thread); + + channel->serverThread = thread; /* update server as new server thread */ + + thread->resource.ipcChannel = channel; + + return NX_EOK; +} + +NX_PRIVATE NX_Error IpcDestroyHelperThread(NX_IpcChannel * channel) +{ + NX_Thread * thread; + NX_Process * process; + + if (!channel) + { + return NX_EINVAL; + } + + thread = channel->serverThread; + NX_ASSERT(thread); + process = NX_ThreadGetProcess(thread); + + NX_ThreadDeququeGlobalListUnlocked(thread); + NX_ProcessDeleteThread(process, thread); + NX_ProcessUnmapTls(process, thread); + NX_VmspaceUnmap(&process->vmspace, (NX_Addr)thread->userStackBase, NX_IPC_THREAD_STACK_SIZE, 0); + NX_ThreadDestroy(thread); + return NX_EOK; +} + +NX_PRIVATE NX_Error IpcCreateShm(NX_Thread * client, NX_Thread * server, NX_Size bufSize, + NX_Addr * outClientBufAddr, NX_Addr * outServerBufAddr, + NX_ShareMem ** outShm) +{ + NX_Addr clientBufAddr; + NX_Addr serverBufAddr; + + /* create share memory */ + NX_ShareMem * shm = NX_ShareMemoryCreate(NX_NULL, bufSize, NX_SHAREMEM_ANONYMOUS); + if (!shm) + { + return NX_ENOMEM; + } + + /* map shm to user space */ + if (NX_ShareMemMapToVmspace(shm, &NX_ThreadGetProcess(server)->vmspace, (void **)&serverBufAddr) != NX_EOK) + { + NX_ShareMemClose(shm); + return NX_ENOMEM; + } + + if (NX_ShareMemMapToVmspace(shm, &NX_ThreadGetProcess(client)->vmspace, (void **)&clientBufAddr) != NX_EOK) + { + NX_ShareMemUnmapFromVmspace(shm, &NX_ThreadGetProcess(server)->vmspace, (void *)serverBufAddr); + NX_ShareMemClose(shm); + return NX_ENOMEM; + } + + *outClientBufAddr = clientBufAddr; + *outServerBufAddr = serverBufAddr; + *outShm = shm; + + return NX_EOK; +} + +NX_PRIVATE void IpcDestroyShm(NX_Vmspace * clientSpcae, NX_Vmspace * serverSpace, NX_ShareMem * shm, + NX_Addr clientBufAddr, NX_Addr serverBufAddr) +{ + NX_ShareMemUnmapFromVmspace(shm, clientSpcae, (void *)clientBufAddr); + NX_ShareMemUnmapFromVmspace(shm, serverSpace, (void *)serverBufAddr); + NX_ShareMemClose(shm); +} + +NX_PRIVATE NX_Error IpcCreateClient(NX_Thread * client, NX_Thread * server, + NX_IpcClientConfig * outConfig, NX_Size bufSize, + NX_IpcChannel ** outConnect) +{ + NX_IpcServer * ipc; + NX_Addr serverBufAddr; + NX_Addr clientBufAddr; + NX_Error err; + NX_IpcChannel * channel; + NX_ShareMem * shm = NX_NULL; + + ipc = server->resource.ipcServer; + + if ((err = IpcCreateShm(client, server, + bufSize, &clientBufAddr, &serverBufAddr, &shm)) != NX_EOK) + { + return err; + } + + channel = NX_IpcCreateChannel(ipc, serverBufAddr, clientBufAddr, bufSize); + if (!channel) + { + IpcDestroyShm(&NX_ThreadGetProcess(client)->vmspace, &NX_ThreadGetProcess(server)->vmspace, + shm, clientBufAddr, serverBufAddr); + return NX_ENOMEM; + } + + /* add thread info and shm */ + channel->clientThread = client; + channel->shm = shm; + /* create server thread */ + if ((err = IpcCreateHelperThread(server, channel, ipc->handler, (void *)serverBufAddr)) != NX_EOK) + { + NX_IpcDestroyChannel(channel); + IpcDestroyShm(&NX_ThreadGetProcess(client)->vmspace, &NX_ThreadGetProcess(server)->vmspace, + shm, clientBufAddr, serverBufAddr); + return err; + } + + NX_AtomicInc(&ipc->channelCount); + + outConfig->bufAddr = channel->buf.clientBufAddr; + outConfig->bufSize = bufSize; + + *outConnect = channel; + + return NX_EOK; +} + +NX_PRIVATE NX_Error IpcDestroyClient(NX_IpcChannel * channel) +{ + NX_ShareMem * shm; + NX_Addr clientBufAddr; + NX_Addr serverBufAddr; + NX_Process * clientProc; + NX_Process * serverProc; + NX_Thread * server; + + shm = channel->shm; + server = channel->serverThread; + + clientProc = NX_ThreadGetProcess((NX_Thread *)channel->clientThread); + /* get process from ipc process, but not server thread */ + serverProc = channel->ipc->process; + + clientBufAddr = channel->buf.clientBufAddr; + serverBufAddr = channel->buf.serverBufAddr; + + /* terminate user thread */ + if (channel->state != NX_IPC_CHANNEL_INIT) + { + while (channel->state != NX_IPC_CHANNEL_CLOSE) + { + NX_SignalSend(server->tid, NX_SIGNAL_KILL, NX_NULL, NX_NULL); + NX_ThreadSleep(50); + } + } + else + { + IpcDestroyHelperThread(channel); + } + + IpcDestroyShm(&clientProc->vmspace, &serverProc->vmspace, + shm, clientBufAddr, serverBufAddr); + NX_IpcDestroyChannel(channel); + + return NX_EOK; +} + +NX_PRIVATE NX_Error IpcChannelCloseSolt(void * object, NX_ExposedObjectType type) +{ + NX_IpcChannel * channel; + NX_IpcServer * ipc; + + if (type != NX_EXOBJ_IPC_CHANNEL) + { + return NX_ENORES; + } + + channel = (NX_IpcChannel *) object; + NX_ASSERT(channel); + ipc = channel->ipc; + + IpcDestroyClient(channel); + NX_AtomicDec(&ipc->channelCount); + + return NX_EOK; +} + +NX_PRIVATE NX_Error SysIpcConnect(const char * name, NX_IpcClientConfig * outConfig, NX_Size bufSize, NX_Solt * outSolt) +{ + NX_IpcServer * ipc; + NX_Thread * client, * server; + NX_IpcClientConfig config; + NX_Error err; + NX_IpcChannel * channel = NX_NULL; + NX_Solt clientSolt = NX_SOLT_INVALID_VALUE; + + if (!name || !outConfig || !bufSize || !outSolt) + { + return NX_EINVAL; + } + + ipc = NX_IpcSearch(name); + if (!ipc) + { + return NX_ENOSRCH; + } + + if (NX_AtomicGet(&ipc->channelCount) >= ipc->maxClient) + { + return NX_ENORES; + } + + client = NX_ThreadSelf(); + server = ipc->thread; + + if ((err = IpcCreateClient(client, server, &config, bufSize, &channel)) != NX_EOK) + { + return err; + } + + /* install channel */ + if ((err = NX_ProcessInstallSolt(NX_ThreadGetProcess(client), channel, + NX_EXOBJ_IPC_CHANNEL, IpcChannelCloseSolt, &clientSolt)) != NX_EOK) + { + IpcDestroyClient(channel); + return err; + } + + NX_CopyToUser((char *)outConfig, (char *)&config, sizeof(NX_IpcClientConfig)); + NX_CopyToUser((char *)outSolt, (char *)&clientSolt, sizeof(clientSolt)); + + return NX_EOK; +} + +NX_PRIVATE NX_Error IpcCloseSolt(void * object, NX_ExposedObjectType type) +{ + NX_IpcServer * ipc; + + if (type != NX_EXOBJ_IPC) + { + return NX_ENORES; + } + + ipc = (NX_IpcServer *) object; + NX_ASSERT(ipc); + + return NX_IpcDestroyServer(ipc); +} + +NX_PRIVATE NX_Error SysIpcBind(const char * name, void * serverHandler, NX_Size maxClient, NX_Solt * outSolt) +{ + NX_Thread * cur; + NX_Error err; + NX_Solt solt; + NX_IpcServer * ipc; + + if (!name || !serverHandler || !maxClient || !outSolt) + { + return NX_EINVAL; + } + + if (NX_StrLen(name) > NX_IPC_NAME_LEN || maxClient >= NX_IPC_CHANNEL_MAX) + { + return NX_EINVAL; + } + + if (NX_IpcSearch(name) != NX_NULL) + { + return NX_EBUSY; + } + + cur = NX_ThreadSelf(); + + if (cur->resource.ipcServer != NX_NULL) + { + return NX_EBUSY; + } + + ipc = NX_IpcCreateServer(name, serverHandler, maxClient); + if (!ipc) + { + return NX_ENOMEM; + } + + ipc->thread = cur; + ipc->process = NX_ThreadGetProcess(cur); + + if ((err = NX_ProcessInstallSolt(NX_ThreadGetProcess(cur), + ipc, NX_EXOBJ_IPC, IpcCloseSolt, &solt)) != NX_EOK) + { + NX_IpcDestroyServer(ipc); + return err; + } + + cur->resource.ipcServer = ipc; + + NX_CopyToUser((char *)outSolt, (char *)&solt, sizeof(solt)); + + return NX_EOK; +} + +NX_PRIVATE NX_Error SysIpcCall(NX_Solt channelSolt, NX_Size * returnValue) +{ + NX_Thread * server, * client; + NX_Thread *cur = NX_CurrentThread; + NX_IpcChannel * channel; + NX_Process * process; + NX_ExposedObject * exobj; + + if (channelSolt == NX_SOLT_INVALID_VALUE || !returnValue) + { + return NX_EINVAL; + } + + process = NX_ProcessCurrent(); + if ((exobj = NX_ProcessGetSolt(process, channelSolt)) == NX_NULL) + { + return NX_ENOSRCH; + } + + if (exobj->type != NX_EXOBJ_IPC_CHANNEL) + { + return NX_ENORES; + } + + channel = (NX_IpcChannel *)exobj->object; + NX_ASSERT(channel); + channel->state = NX_IPC_CHANNEL_ACTIVE; + + server = channel->serverThread; + NX_ASSERT(server); + client = channel->clientThread; + NX_ASSERT(client); + + /* reset server state */ + server->stack = server->stackBase + server->stackSize - sizeof(NX_UArch); + server->stack = NX_ContextInit(NX_UserThreadEntry, (void *)NX_ThreadExit, + (void *)channel->buf.serverBufAddr, server->stack); + + /* sched to server */ + NX_UArch level = NX_IRQ_SaveLevel(); + cur->state = NX_THREAD_BLOCKED; + NX_SchedLockedIRQ(level, NX_NULL, server); + + if (returnValue) + { + NX_CopyToUser((char *)returnValue, (char *)&channel->returnValue, sizeof(NX_Size)); + } + + return NX_EOK; +} + +NX_PRIVATE NX_Error SysIpcReturn(NX_Size returnValue) +{ + NX_Thread * self = NX_ThreadSelf(); + NX_IpcChannel * channel; + + channel = self->resource.ipcChannel; + + if (self->resource.ipcServer != NX_NULL || channel == NX_NULL) + { + return NX_EPERM; + } + + channel->returnValue = returnValue; + channel->state = NX_IPC_CHANNEL_DEACTIVE; + + /* sched to client */ + NX_UArch level = NX_IRQ_SaveLevel(); + self->state = NX_THREAD_BLOCKED; + NX_SchedLockedIRQ(level, NX_NULL, channel->clientThread); + + /** + * server thread should never arrive here, but if channel closed, + * will send a terminate signal to server thread, just return INTR. + */ + return NX_EINTR; +} + /* xbook env syscall table */ NX_PRIVATE const NX_SyscallHandler NX_SyscallTable[] = { @@ -2185,6 +2616,10 @@ NX_PRIVATE const NX_SyscallHandler NX_SyscallTable[] = SysPollWait, SysShareMemOpen, /* 85 */ SysShareMemMap, + SysIpcBind, + SysIpcConnect, + SysIpcCall, + SysIpcReturn, }; /* posix env syscall table */ diff --git a/src/sched/sched.c b/src/sched/sched.c index 079e01a..7d66b81 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -21,7 +21,6 @@ #include #include -NX_IMPORT NX_ThreadManager gThreadManagerObject; NX_IMPORT NX_Atomic gActivedCoreCount; NX_INLINE void SchedSwithProcess(NX_Thread *thread) @@ -124,7 +123,7 @@ NX_PRIVATE void PullOrPushThread(NX_UArch coreId) * @lock: if not NX_NULL, the lock need unblock before sched to other thread * @lockIrqLevel: lock irq level */ -void NX_SchedLockedIRQ(NX_UArch irqLevel, NX_Spin *lock) +void NX_SchedLockedIRQ(NX_UArch irqLevel, NX_Spin *lock, void * nextThread) { NX_Thread *next, *prev; NX_UArch coreId = NX_SMP_GetIdx(); @@ -140,8 +139,15 @@ void NX_SchedLockedIRQ(NX_UArch irqLevel, NX_Spin *lock) /* pull thread from pending list or push thread to pending list */ PullOrPushThread(coreId); - /* get next from local list */ - next = NX_SMP_PickThreadIrqDisabled(coreId); + if (!nextThread) + { + /* get next from local list */ + next = NX_SMP_PickThreadIrqDisabled(coreId); + } + else + { + next = nextThread; + } NX_ASSERT(next != NX_NULL); NX_SMP_SetRunning(coreId, next); @@ -169,7 +175,7 @@ void NX_SchedLockedIRQ(NX_UArch irqLevel, NX_Spin *lock) */ void NX_SchedInterruptDisabled(NX_UArch irqLevel) { - NX_SchedLockedIRQ(irqLevel, NX_NULL); + NX_SchedLockedIRQ(irqLevel, NX_NULL, NX_NULL); } void NX_SchedYield(void) diff --git a/src/sched/thread.c b/src/sched/thread.c index fb37091..023a09e 100644 --- a/src/sched/thread.c +++ b/src/sched/thread.c @@ -79,7 +79,9 @@ NX_PRIVATE NX_Error ThreadInit(NX_Thread *thread, thread->resource.process = NX_NULL; thread->resource.fileTable = NX_FileTableGetDefault(); thread->resource.hub = NX_NULL; + thread->resource.ipcServer = NX_NULL; thread->resource.activeChannel = NX_NULL; + thread->resource.ipcChannel = NX_NULL; thread->resource.exitCode = 0; thread->resource.waitExitCode = 0; NX_SemaphoreInit(&thread->resource.waiterSem, 0); @@ -266,18 +268,6 @@ void NX_ThreadUnreadyRun(NX_Thread *thread) } } -NX_INLINE void NX_ThreadEnququeGlobalListUnlocked(NX_Thread *thread) -{ - NX_ListAdd(&thread->globalList, &gThreadManagerObject.globalList); - NX_AtomicInc(&gThreadManagerObject.activeThreadCount); -} - -NX_INLINE void NX_ThreadDeququeGlobalListUnlocked(NX_Thread *thread) -{ - NX_ListDel(&thread->globalList); - NX_AtomicDec(&gThreadManagerObject.activeThreadCount); -} - NX_Error NX_ThreadStart(NX_Thread *thread) { if (thread == NX_NULL) @@ -363,6 +353,12 @@ NX_PRIVATE void ThreadReleaseResouce(NX_Thread *thread) { NX_MUTEX_UNLOCK_OK(lock); /* unlock the lock */ } + + /* exit channel resource */ + if (thread->resource.ipcChannel) + { + thread->resource.ipcChannel->state = NX_IPC_CHANNEL_CLOSE; + } } void NX_ThreadExit(NX_U32 exitCode) @@ -427,7 +423,7 @@ NX_Error NX_ThreadBlockLockedIRQ(NX_Thread *thread, NX_Spin *lock, NX_UArch irqL NX_POST_THREAD_HOOK(thread); - NX_SchedLockedIRQ(irqLevel, lock); + NX_SchedLockedIRQ(irqLevel, lock, NX_NULL); if (NX_ThreadCheckInterrupt(thread)) { -- Gitee