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