summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/kernel/msg.H28
-rw-r--r--src/include/kernel/syscalls.H10
-rw-r--r--src/include/string.h1
-rw-r--r--src/include/sys/msg.h47
-rw-r--r--src/include/util/locked/list.H153
-rw-r--r--src/include/util/locked/queue.H2
-rw-r--r--src/kernel/syscall.C154
-rw-r--r--src/lib/makefile2
-rw-r--r--src/lib/string.c21
-rw-r--r--src/lib/syscall_msg.C65
-rw-r--r--src/sys/init/init_main.C9
11 files changed, 490 insertions, 2 deletions
diff --git a/src/include/kernel/msg.H b/src/include/kernel/msg.H
new file mode 100644
index 000000000..7a32197f5
--- /dev/null
+++ b/src/include/kernel/msg.H
@@ -0,0 +1,28 @@
+#ifndef __KERNEL_MSG_H
+#define __KERNEL_MSG_H
+
+#include <kernel/types.h>
+#include <sys/msg.h>
+#include <util/locked/list.H>
+#include <util/locked/queue.H>
+
+struct MessagePending
+{
+ typedef msg_t* key_type;
+ key_type key;
+ task_t* task;
+
+ MessagePending* prev;
+ MessagePending* next;
+};
+
+class MessageQueue
+{
+ public:
+ Spinlock lock;
+ Util::Locked::List<MessagePending, MessagePending::key_type> messages;
+ Util::Locked::List<MessagePending, MessagePending::key_type> responses;
+ Util::Locked::Queue<task_t> waiting;
+};
+
+#endif
diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H
index ebe7d0059..9a0672d63 100644
--- a/src/include/kernel/syscalls.H
+++ b/src/include/kernel/syscalls.H
@@ -15,6 +15,16 @@ namespace Systemcalls
MUTEX_LOCK_CONTESTED,
MUTEX_UNLOCK_CONTESTED,
+ MSGQ_CREATE,
+ MSGQ_DESTROY,
+ MSGQ_REGISTER_ROOT,
+ MSGQ_RESOLVE_ROOT,
+
+ MSG_SEND,
+ MSG_SENDRECV,
+ MSG_RESPOND,
+ MSG_WAIT,
+
SYSCALL_MAX
};
};
diff --git a/src/include/string.h b/src/include/string.h
index f1465a4c0..a2b704067 100644
--- a/src/include/string.h
+++ b/src/include/string.h
@@ -9,6 +9,7 @@ extern "C"
#endif
void* memset(void* s, int c, size_t n);
+ int strcmp(const char* s1, const char* s2);
#ifdef __cplusplus
};
diff --git a/src/include/sys/msg.h b/src/include/sys/msg.h
new file mode 100644
index 000000000..ca5dab7e6
--- /dev/null
+++ b/src/include/sys/msg.h
@@ -0,0 +1,47 @@
+#ifndef __SYS_MSG_H
+#define __SYS_MSG_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef void* msg_q_t;
+
+struct msg_t
+{
+ uint32_t type;
+ uint32_t __reserved__async;
+ uint64_t data[2];
+ void* extra_data;
+};
+
+// Message queue interfaces.
+msg_q_t msg_q_create();
+int msg_q_destroy();
+int msg_q_register(msg_q_t q, char* name);
+msg_q_t msg_q_resolve(char* name);
+
+// Message interfaces.
+__attribute__((always_inline))
+ inline msg_t* msg_allocate() { return (msg_t*)malloc(sizeof(msg_t)); }
+__attribute__((always_inline))
+ inline void msg_free(msg_t* m) { free(m); }
+
+int msg_send(msg_q_t q, msg_t* msg);
+int msg_sendrecv(msg_q_t q, msg_t* msg);
+int msg_respond(msg_q_t q, msg_t* msg);
+msg_t* msg_wait(msg_q_t q);
+
+__attribute__((always_inline))
+ inline uint32_t msg_is_async(msg_t* msg)
+ { return 0 == msg->__reserved__async; }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/util/locked/list.H b/src/include/util/locked/list.H
new file mode 100644
index 000000000..e4bc0f99c
--- /dev/null
+++ b/src/include/util/locked/list.H
@@ -0,0 +1,153 @@
+#ifndef __UTIL_LOCKED_LIST_H
+#define __UTIL_LOCKED_LIST_H
+
+#include <util/locked/lock.H>
+
+namespace Util
+{
+ namespace Locked
+ {
+ template <typename _T, typename _K,
+ bool locked = false, typename _S = int>
+ class List
+ {
+ public:
+ List() : head(NULL), tail(NULL), lock() {};
+ ~List() {};
+
+ _T* remove();
+ void insert(_T*);
+
+ void erase(_T* node);
+ void erase(_K& key);
+
+ _T* find(_K& key);
+
+ protected:
+ _T* head;
+ _T* tail;
+
+ _S lock;
+
+ void __lock();
+ void __unlock();
+ };
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ _T* List<_T,_K,locked,_S>::remove()
+ {
+ _T* item = NULL;
+
+ __lock();
+
+ if (tail != NULL)
+ {
+ item = tail;
+ if (head == tail)
+ head = tail = NULL;
+ else
+ tail = item->prev;
+ }
+
+ __unlock();
+
+ return item;
+ }
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ void List<_T,_K,locked,_S>::insert(_T* item)
+ {
+ __lock();
+
+ if (head == NULL)
+ {
+ item->next = item->prev = NULL;
+ head = tail = item;
+ }
+ else
+ {
+ item->prev = NULL;
+ item->next = head;
+ head = head->prev = item;
+ }
+
+ __unlock();
+ }
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ void List<_T,_K,locked,_S>::__lock()
+ {
+ Util::Locked::LockHelper<locked,_S>(lock).lock();
+ }
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ void List<_T,_K,locked,_S>::__unlock()
+ {
+ Util::Locked::LockHelper<locked,_S>(lock).unlock();
+ }
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ void List<_T,_K,locked,_S>::erase(_T* node)
+ {
+ __lock();
+
+ if (node == head)
+ head = node->next;
+ else
+ node->prev->next = node->next;
+
+ if (node == tail)
+ tail = node->prev;
+ else
+ node->next->prev = node->prev;
+
+ __unlock();
+ }
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ void List<_T,_K,locked,_S>::erase(_K& key)
+ {
+ __lock();
+
+ _T* node = head;
+
+ while((node != NULL) && (node->key != key))
+ node = node->next;
+
+ if (node != NULL)
+ {
+ if (node == head)
+ head = node->next;
+ else
+ node->prev->next = node->next;
+
+ if (node == tail)
+ tail = node->prev;
+ else
+ node->next->prev = node->prev;
+ }
+
+ __unlock();
+
+ return node;
+ }
+
+ template <typename _T, typename _K, bool locked, typename _S>
+ _T* List<_T,_K,locked,_S>::find(_K& key)
+ {
+ __lock();
+
+ _T* node = head;
+
+ while((node != NULL) && (node->key != key))
+ node = node->next;
+
+ __unlock();
+
+ return node;
+ }
+ }
+}
+
+
+#endif
diff --git a/src/include/util/locked/queue.H b/src/include/util/locked/queue.H
index 51d2c430e..651e24a80 100644
--- a/src/include/util/locked/queue.H
+++ b/src/include/util/locked/queue.H
@@ -17,7 +17,7 @@ namespace Util
_T* remove();
void insert(_T*);
- private:
+ protected:
_T* head;
_T* tail;
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index d3cff262c..b969745ca 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -7,6 +7,7 @@
#include <kernel/console.H>
#include <kernel/pagemgr.H>
#include <kernel/usermutex.H>
+#include <kernel/msg.H>
extern "C"
void kernel_execute_decrementer()
@@ -31,6 +32,14 @@ namespace Systemcalls
void MutexDestroy(task_t*);
void MutexLockCont(task_t*);
void MutexUnlockCont(task_t*);
+ void MsgQCreate(task_t*);
+ void MsgQDestroy(task_t*);
+ void MsgQRegisterRoot(task_t*);
+ void MsgQResolveRoot(task_t*);
+ void MsgSend(task_t*);
+ void MsgSendRecv(task_t*);
+ void MsgRespond(task_t*);
+ void MsgWait(task_t*);
syscall syscalls[] =
{
@@ -43,6 +52,16 @@ namespace Systemcalls
&MutexDestroy,
&MutexLockCont,
&MutexUnlockCont,
+
+ &MsgQCreate,
+ &MsgQDestroy,
+ &MsgQRegisterRoot,
+ &MsgQResolveRoot,
+
+ &MsgSend,
+ &MsgSendRecv,
+ &MsgRespond,
+ &MsgWait,
};
};
@@ -169,4 +188,139 @@ namespace Systemcalls
m->lock.unlock();
TASK_SETRTN(t, 0);
}
+
+ void MsgQCreate(task_t* t)
+ {
+ TASK_SETRTN(t, (uint64_t) new MessageQueue());
+ }
+
+ void MsgQDestroy(task_t* t)
+ {
+ MessageQueue* mq = (MessageQueue*) TASK_GETARG0(t);
+ if (NULL != mq)
+ delete mq;
+ TASK_SETRTN(t, 0);
+ }
+
+ static MessageQueue* msgQRoot = NULL;
+
+ void MsgQRegisterRoot(task_t* t)
+ {
+ msgQRoot = (MessageQueue*) TASK_GETARG0(t);
+ TASK_SETRTN(t, 0);
+ }
+
+ void MsgQResolveRoot(task_t* t)
+ {
+ TASK_SETRTN(t, (uint64_t) msgQRoot);
+ }
+
+ void MsgSend(task_t* t)
+ {
+ MessageQueue* mq = (MessageQueue*) TASK_GETARG0(t);
+ msg_t* m = (msg_t*) TASK_GETARG1(t);
+ m->__reserved__async = 0; // set to async msg.
+
+ mq->lock.lock();
+
+ // Get waiting (server) task.
+ task_t* waiter = mq->waiting.remove();
+ if (NULL == waiter) // None found, add to 'messages' queue.
+ {
+ MessagePending* mp = new MessagePending();
+ mp->key = m;
+ mp->task = t;
+ mq->messages.insert(mp);
+ }
+ else // Add waiter back to its scheduler.
+ {
+ TASK_SETRTN(waiter, (uint64_t) m);
+ waiter->cpu->scheduler->addTask(waiter);
+ }
+
+ mq->lock.unlock();
+ TASK_SETRTN(t, 0);
+ }
+
+ void MsgSendRecv(task_t* t)
+ {
+ MessageQueue* mq = (MessageQueue*) TASK_GETARG0(t);
+ msg_t* m = (msg_t*) TASK_GETARG1(t);
+ m->__reserved__async = 1; // set to sync msg.
+
+ mq->lock.lock();
+ MessagePending* mp = new MessagePending();
+ mp->key = m;
+ mp->task = t;
+
+ // Get waiting (server) task.
+ task_t* waiter = mq->waiting.remove();
+ if (NULL == waiter) // None found, add to 'messages' queue.
+ {
+ mq->messages.insert(mp);
+ }
+ else // Context switch to waiter.
+ {
+ TASK_SETRTN(waiter, (uint64_t) m);
+ mq->responses.insert(mp);
+ waiter->cpu = t->cpu;
+ TaskManager::setCurrentTask(waiter);
+ }
+
+ mq->lock.unlock();
+ TASK_SETRTN(t,0);
+ }
+
+ void MsgRespond(task_t* t)
+ {
+ MessageQueue* mq = (MessageQueue*) TASK_GETARG0(t);
+ msg_t* m = (msg_t*) TASK_GETARG1(t);
+
+ mq->lock.lock();
+ MessagePending* mp = mq->responses.find(m);
+ if (NULL != mp)
+ {
+ task_t* waiter = mp->task;
+
+ mq->responses.erase(mp);
+ delete mp;
+
+ waiter->cpu = t->cpu;
+ TaskManager::setCurrentTask(waiter);
+ t->cpu->scheduler->addTask(t);
+
+ TASK_SETRTN(t,0);
+ }
+ else
+ {
+ TASK_SETRTN(t, -1);
+ }
+ mq->lock.unlock();
+ }
+
+ void MsgWait(task_t* t)
+ {
+ MessageQueue* mq = (MessageQueue*) TASK_GETARG0(t);
+
+ mq->lock.lock();
+ MessagePending* mp = mq->messages.remove();
+
+ if (NULL == mp)
+ {
+ mq->waiting.insert(t);
+ t->cpu->scheduler->setNextRunnable();
+ }
+ else
+ {
+ msg_t* m = mp->key;
+ if (m->__reserved__async)
+ mq->responses.insert(mp);
+ else
+ delete mp;
+ TASK_SETRTN(t, (uint64_t) m);
+ }
+ mq->lock.unlock();
+ }
+
+
};
diff --git a/src/lib/makefile b/src/lib/makefile
index 718a8219e..febe3f27f 100644
--- a/src/lib/makefile
+++ b/src/lib/makefile
@@ -2,7 +2,7 @@ OBJDIR = ../../obj
include ../../config.mk
OBJS = string.o stdlib.o
-OBJS += syscall_stub.o syscall_task.o syscall_mutex.o
+OBJS += syscall_stub.o syscall_task.o syscall_mutex.o syscall_msg.o
OBJECTS = $(addprefix ${OBJDIR}/, ${OBJS})
all: ${OBJECTS}
diff --git a/src/lib/string.c b/src/lib/string.c
index b84de213f..fb4d435ae 100644
--- a/src/lib/string.c
+++ b/src/lib/string.c
@@ -9,3 +9,24 @@ void* memset(void* s, int c, size_t n)
_s++; n--;
}
}
+
+int strcmp(const char* a, const char* b)
+{
+ while((*a != '\0') && (*b != '\0'))
+ {
+ if (*a == *b)
+ {
+ a++; b++;
+ }
+ else
+ {
+ return (*a > *b) ? 1 : -1;
+ }
+ }
+ if (*a == *b)
+ return 0;
+ if (*a == '\0')
+ return -1;
+ else
+ return 1;
+}
diff --git a/src/lib/syscall_msg.C b/src/lib/syscall_msg.C
new file mode 100644
index 000000000..774ddb0bb
--- /dev/null
+++ b/src/lib/syscall_msg.C
@@ -0,0 +1,65 @@
+#include <sys/msg.h>
+#include <sys/syscall.h>
+
+#include <string.h>
+
+using namespace Systemcalls;
+
+const char* VFS_ROOT = "/"; // TODO.
+
+msg_q_t msg_q_create()
+{
+ return (msg_q_t) _syscall0(MSGQ_CREATE);
+}
+
+int msg_q_destroy(msg_q_t q)
+{
+ return (int64_t)_syscall1(MSGQ_DESTROY, q);
+}
+
+int msg_q_register(msg_q_t q, char* name)
+{
+ if (0 == strcmp(VFS_ROOT, name))
+ {
+ return (int64_t)_syscall1(MSGQ_REGISTER_ROOT, q);
+ }
+ else
+ {
+ // TODO.
+ return -1;
+ }
+}
+
+msg_q_t msg_q_resolve(char* name)
+{
+ if (0 == strcmp(VFS_ROOT, name))
+ {
+ return (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
+ }
+ else
+ {
+ // TODO.
+ return NULL;
+ }
+}
+
+int msg_send(msg_q_t q, msg_t* msg)
+{
+ return (int64_t)_syscall2(MSG_SEND, q, msg);
+}
+
+int msg_sendrecv(msg_q_t q, msg_t* msg)
+{
+ return (int64_t)_syscall2(MSG_SENDRECV, q, msg);
+}
+
+int msg_respond(msg_q_t q, msg_t* msg)
+{
+ return (int64_t)_syscall2(MSG_RESPOND, q, msg);
+}
+
+msg_t* msg_wait(msg_q_t q)
+{
+ return (msg_t*)_syscall1(MSG_WAIT, q);
+}
+
diff --git a/src/sys/init/init_main.C b/src/sys/init/init_main.C
index efeddcafd..c11b4ef97 100644
--- a/src/sys/init/init_main.C
+++ b/src/sys/init/init_main.C
@@ -2,6 +2,7 @@
#include <sys/task.h>
#include <sys/mutex.h>
+#include <sys/msg.h>
mutex_t global_mutex;
@@ -19,6 +20,14 @@ void init_main(void* unused)
global_mutex = mutex_create();
+ msg_q_t msgq = msg_q_create();
+ msg_t* msg = msg_allocate();
+ msg->type = 1; msg->data[0] = 0xDEADBEEF12345678;
+ msg_send(msgq, msg);
+ msg = msg_wait(msgq);
+
+ printk("Got Message: %llx\n", msg->data[0]);
+
while(1)
{
mutex_lock(global_mutex);
OpenPOWER on IntegriCloud