Implemented send_data/receive_data/has_data thread syscalls
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@815 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -352,6 +352,10 @@ int suspend_thread(thread_id thread);
|
|||||||
|
|
||||||
thread_id find_thread(const char *);
|
thread_id find_thread(const char *);
|
||||||
|
|
||||||
|
status_t send_data(thread_id thread, int32 code, const void *buffer, size_t buffer_size);
|
||||||
|
status_t receive_data(thread_id *sender, void *buffer, size_t buffer_size);
|
||||||
|
bool has_data(thread_id thread);
|
||||||
|
|
||||||
status_t snooze(bigtime_t);
|
status_t snooze(bigtime_t);
|
||||||
|
|
||||||
status_t _get_thread_info(thread_id id, thread_info *info, size_t size);
|
status_t _get_thread_info(thread_id id, thread_info *info, size_t size);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include <stage2.h>
|
#include <stage2.h>
|
||||||
#include <ktypes.h>
|
#include <ktypes.h>
|
||||||
|
#include <cbuf.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <arch/thread_struct.h>
|
#include <arch/thread_struct.h>
|
||||||
@@ -108,6 +109,14 @@ struct thread {
|
|||||||
int sem_deleted_retcode;
|
int sem_deleted_retcode;
|
||||||
int sem_errcode;
|
int sem_errcode;
|
||||||
int sem_flags;
|
int sem_flags;
|
||||||
|
struct {
|
||||||
|
sem_id write_sem;
|
||||||
|
sem_id read_sem;
|
||||||
|
thread_id sender;
|
||||||
|
int32 code;
|
||||||
|
size_t size;
|
||||||
|
cbuf *buffer;
|
||||||
|
} msg;
|
||||||
addr fault_handler;
|
addr fault_handler;
|
||||||
addr entry;
|
addr entry;
|
||||||
void *args;
|
void *args;
|
||||||
|
|||||||
@@ -102,6 +102,9 @@ enum {
|
|||||||
SYSCALL_GET_NEXT_TEAM_INFO,
|
SYSCALL_GET_NEXT_TEAM_INFO,
|
||||||
SYSCALL_CREATE_LINK,
|
SYSCALL_CREATE_LINK,
|
||||||
SYSCALL_REMOVE_DIR,
|
SYSCALL_REMOVE_DIR,
|
||||||
|
SYSCALL_SEND_DATA,
|
||||||
|
SYSCALL_RECEIVE_DATA,
|
||||||
|
SYSCALL_HAS_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret);
|
int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret);
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ int user_team_wait_on_team(team_id id, int *uretcode);
|
|||||||
thread_id user_thread_create_user_thread(addr, team_id, const char*,
|
thread_id user_thread_create_user_thread(addr, team_id, const char*,
|
||||||
int, void *);
|
int, void *);
|
||||||
|
|
||||||
|
status_t user_send_data(thread_id thread, int32 code, const void *buffer, size_t buffer_size);
|
||||||
|
status_t user_receive_data(thread_id *sender, void *buffer, size_t buffer_size);
|
||||||
|
|
||||||
status_t user_get_thread_info(thread_id id, thread_info *info);
|
status_t user_get_thread_info(thread_id id, thread_info *info);
|
||||||
status_t user_get_next_thread_info(team_id team, int32 *cookie, thread_info *info);
|
status_t user_get_next_thread_info(team_id team, int32 *cookie, thread_info *info);
|
||||||
status_t user_get_team_info(team_id id, team_info *info);
|
status_t user_get_team_info(team_id id, team_info *info);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ static int priority_test(void *data)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i<10; i++) {
|
for (i=0; i<6; i++) {
|
||||||
printf("%s: %d\n", (char *)data, i);
|
printf("%s: %d\n", (char *)data, i);
|
||||||
// sys_snooze(1000);
|
// sys_snooze(1000);
|
||||||
}
|
}
|
||||||
@@ -44,12 +44,32 @@ static int priority_test(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int communication_test(void *data)
|
||||||
|
{
|
||||||
|
int times = (int)data;
|
||||||
|
int i, code;
|
||||||
|
char buffer[1024];
|
||||||
|
thread_id sender;
|
||||||
|
|
||||||
|
for (i=0; i<times; i++) {
|
||||||
|
code = receive_data(&sender, (void *)buffer, sizeof(buffer));
|
||||||
|
printf(" -> received (%d): \"%s\"\n", code, buffer);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
thread_id t[THREADS];
|
thread_id t[THREADS];
|
||||||
sem_id lock;
|
sem_id lock;
|
||||||
int i;
|
int i;
|
||||||
int expected = START_VAL, current_val = START_VAL;
|
int expected = START_VAL, current_val = START_VAL;
|
||||||
|
char *comm_test[] = { "This is a test",
|
||||||
|
"of the send_data",
|
||||||
|
"and receive_data",
|
||||||
|
"syscalls implementation",
|
||||||
|
"for OpenBeOS" };
|
||||||
|
|
||||||
printf("OpenBeOS Thread Test - Simple\n"
|
printf("OpenBeOS Thread Test - Simple\n"
|
||||||
"=============================\n");
|
"=============================\n");
|
||||||
@@ -75,12 +95,29 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
delete_sem(lock);
|
delete_sem(lock);
|
||||||
|
|
||||||
t[0] = spawn_thread(priority_test, "thread0", B_DISPLAY_PRIORITY, "thread0");
|
t[0] = spawn_thread(priority_test, "thread0", 11, "thread0");
|
||||||
t[1] = spawn_thread(priority_test, "thread1", B_URGENT_DISPLAY_PRIORITY, "thread1");
|
t[1] = spawn_thread(priority_test, "thread1", 12, "thread1");
|
||||||
|
t[2] = spawn_thread(priority_test, "thread2", 13, "thread2");
|
||||||
resume_thread(t[0]);
|
resume_thread(t[0]);
|
||||||
resume_thread(t[1]);
|
resume_thread(t[1]);
|
||||||
|
resume_thread(t[2]);
|
||||||
|
|
||||||
|
sys_snooze(100000);
|
||||||
|
|
||||||
sys_wait_on_thread(t[0], NULL);
|
sys_wait_on_thread(t[0], NULL);
|
||||||
sys_wait_on_thread(t[1], NULL);
|
sys_wait_on_thread(t[1], NULL);
|
||||||
|
sys_wait_on_thread(t[2], NULL);
|
||||||
|
|
||||||
|
t[0] = spawn_thread(communication_test, "commthread", B_NORMAL_PRIORITY, (void *)5);
|
||||||
|
resume_thread(t[0]);
|
||||||
|
|
||||||
|
for (i=0; i<5; i++) {
|
||||||
|
printf("sending");
|
||||||
|
send_data(t[0], i, comm_test[i], strlen(comm_test[i]) + 1);
|
||||||
|
// Give time to the commthread to display info
|
||||||
|
sys_snooze(10000);
|
||||||
|
}
|
||||||
|
sys_wait_on_thread(t[0], NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,6 +219,15 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re
|
|||||||
case SYSCALL_RESUME_THREAD:
|
case SYSCALL_RESUME_THREAD:
|
||||||
*call_ret = thread_resume_thread((thread_id)arg0);
|
*call_ret = thread_resume_thread((thread_id)arg0);
|
||||||
break;
|
break;
|
||||||
|
case SYSCALL_SEND_DATA:
|
||||||
|
*call_ret = user_send_data((thread_id)arg0, (int32)arg1, (const void *)arg2, (size_t)arg3);
|
||||||
|
break;
|
||||||
|
case SYSCALL_RECEIVE_DATA:
|
||||||
|
*call_ret = user_receive_data((thread_id *)arg0, (void *)arg1, (size_t)arg2);
|
||||||
|
break;
|
||||||
|
case SYSCALL_HAS_DATA:
|
||||||
|
*call_ret = has_data((thread_id)arg0);
|
||||||
|
break;
|
||||||
case SYSCALL_KILL_TEAM:
|
case SYSCALL_KILL_TEAM:
|
||||||
*call_ret = team_kill_team((team_id)arg0);
|
*call_ret = team_kill_team((team_id)arg0);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+169
-10
@@ -35,6 +35,7 @@
|
|||||||
#include <kerrors.h>
|
#include <kerrors.h>
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
|
|
||||||
|
#define THREAD_MAX_MESSAGE_SIZE 65536
|
||||||
|
|
||||||
struct thread_key {
|
struct thread_key {
|
||||||
thread_id id;
|
thread_id id;
|
||||||
@@ -214,6 +215,7 @@ static struct thread *create_thread_struct(const char *name)
|
|||||||
{
|
{
|
||||||
struct thread *t;
|
struct thread *t;
|
||||||
int state;
|
int state;
|
||||||
|
char temp[64];
|
||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
@@ -247,21 +249,32 @@ static struct thread *create_thread_struct(const char *name)
|
|||||||
t->in_kernel = true;
|
t->in_kernel = true;
|
||||||
t->user_time = 0;
|
t->user_time = 0;
|
||||||
t->kernel_time = 0;
|
t->kernel_time = 0;
|
||||||
t->last_time = 0;
|
t->last_time = 0;
|
||||||
{
|
|
||||||
char temp[64];
|
|
||||||
|
|
||||||
sprintf(temp, "thread_0x%x_retcode_sem", t->id);
|
sprintf(temp, "thread_0x%x_retcode_sem", t->id);
|
||||||
t->return_code_sem = create_sem(0, temp);
|
t->return_code_sem = create_sem(0, temp);
|
||||||
if(t->return_code_sem < 0)
|
if(t->return_code_sem < 0)
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
|
||||||
|
sprintf(temp, "%s data write sem", t->name);
|
||||||
|
t->msg.write_sem = create_sem(1, temp);
|
||||||
|
if (t->msg.write_sem < 0)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
sprintf(temp, "%s data read sem", t->name);
|
||||||
|
t->msg.read_sem = create_sem(0, temp);
|
||||||
|
if (t->msg.read_sem < 0)
|
||||||
|
goto err3;
|
||||||
|
|
||||||
if(arch_thread_init_thread_struct(t) < 0)
|
if(arch_thread_init_thread_struct(t) < 0)
|
||||||
goto err2;
|
goto err4;
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
|
err4:
|
||||||
|
delete_sem_etc(t->msg.read_sem, -1);
|
||||||
|
err3:
|
||||||
|
delete_sem_etc(t->msg.write_sem, -1);
|
||||||
err2:
|
err2:
|
||||||
delete_sem_etc(t->return_code_sem, -1);
|
delete_sem_etc(t->return_code_sem, -1);
|
||||||
err1:
|
err1:
|
||||||
@@ -272,8 +285,12 @@ err:
|
|||||||
|
|
||||||
static void delete_thread_struct(struct thread *t)
|
static void delete_thread_struct(struct thread *t)
|
||||||
{
|
{
|
||||||
if(t->return_code_sem >= 0)
|
if (t->return_code_sem >= 0)
|
||||||
delete_sem_etc(t->return_code_sem, -1);
|
delete_sem_etc(t->return_code_sem, -1);
|
||||||
|
if (t->msg.write_sem >= 0)
|
||||||
|
delete_sem_etc(t->msg.write_sem, -1);
|
||||||
|
if (t->msg.read_sem >= 0)
|
||||||
|
delete_sem_etc(t->msg.read_sem, -1);
|
||||||
kfree(t);
|
kfree(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1309,6 +1326,148 @@ void thread_atkernel_exit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
user_send_data(thread_id tid, int32 code, const void *buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
if (((addr)buffer >= KERNEL_BASE) && ((addr)buffer <= KERNEL_TOP))
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
return send_data(tid, code, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
send_data(thread_id tid, int32 code, const void *buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
struct thread *target;
|
||||||
|
sem_id cached_sem;
|
||||||
|
int state;
|
||||||
|
status_t rv;
|
||||||
|
cbuf *data;
|
||||||
|
|
||||||
|
state = disable_interrupts();
|
||||||
|
GRAB_THREAD_LOCK();
|
||||||
|
target = thread_get_thread_struct_locked(tid);
|
||||||
|
if (!target) {
|
||||||
|
RELEASE_THREAD_LOCK();
|
||||||
|
restore_interrupts(state);
|
||||||
|
return B_BAD_THREAD_ID;
|
||||||
|
}
|
||||||
|
cached_sem = target->msg.write_sem;
|
||||||
|
RELEASE_THREAD_LOCK();
|
||||||
|
restore_interrupts(state);
|
||||||
|
|
||||||
|
if (buffer_size > THREAD_MAX_MESSAGE_SIZE)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
rv = acquire_sem_etc(cached_sem, 1, B_CAN_INTERRUPT, 0);
|
||||||
|
if (rv == B_INTERRUPTED)
|
||||||
|
// We got interrupted by a signal
|
||||||
|
return rv;
|
||||||
|
if (rv != B_OK)
|
||||||
|
// Any other acquisition problems may be due to thread deletion
|
||||||
|
return B_BAD_THREAD_ID;
|
||||||
|
|
||||||
|
if (buffer_size > 0) {
|
||||||
|
data = cbuf_get_chain(buffer_size);
|
||||||
|
if (!data)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
rv = cbuf_user_memcpy_to_chain(data, 0, buffer, buffer_size);
|
||||||
|
if (rv < 0) {
|
||||||
|
cbuf_free_chain(data);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
data = NULL;
|
||||||
|
|
||||||
|
state = disable_interrupts();
|
||||||
|
GRAB_THREAD_LOCK();
|
||||||
|
|
||||||
|
// The target thread could have been deleted at this point
|
||||||
|
target = thread_get_thread_struct_locked(tid);
|
||||||
|
if (!target) {
|
||||||
|
RELEASE_THREAD_LOCK();
|
||||||
|
restore_interrupts(state);
|
||||||
|
cbuf_free_chain(data);
|
||||||
|
return B_BAD_THREAD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save message informations
|
||||||
|
target->msg.sender = thread_get_current_thread()->id;
|
||||||
|
target->msg.code = code;
|
||||||
|
target->msg.size = buffer_size;
|
||||||
|
target->msg.buffer = data;
|
||||||
|
cached_sem = target->msg.read_sem;
|
||||||
|
|
||||||
|
RELEASE_THREAD_LOCK();
|
||||||
|
restore_interrupts(state);
|
||||||
|
|
||||||
|
release_sem(cached_sem);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
user_receive_data(thread_id *sender, void *buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
thread_id ksender;
|
||||||
|
status_t code;
|
||||||
|
status_t rv;
|
||||||
|
|
||||||
|
if (((addr)sender >= KERNEL_BASE) && ((addr)sender <= KERNEL_TOP))
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
if (((addr)buffer >= KERNEL_BASE) && ((addr)buffer <= KERNEL_TOP))
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
code = receive_data(&ksender, buffer, buffer_size);
|
||||||
|
|
||||||
|
rv = user_memcpy(sender, &ksender, sizeof(thread_id));
|
||||||
|
if (rv < 0)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
receive_data(thread_id *sender, void *buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
struct thread *t = thread_get_current_thread();
|
||||||
|
status_t rv;
|
||||||
|
size_t size;
|
||||||
|
int32 code;
|
||||||
|
|
||||||
|
acquire_sem(t->msg.read_sem);
|
||||||
|
|
||||||
|
size = min(buffer_size, t->msg.size);
|
||||||
|
rv = cbuf_user_memcpy_from_chain(buffer, t->msg.buffer, 0, size);
|
||||||
|
if (rv < 0) {
|
||||||
|
cbuf_free_chain(t->msg.buffer);
|
||||||
|
release_sem(t->msg.write_sem);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sender = t->msg.sender;
|
||||||
|
code = t->msg.code;
|
||||||
|
|
||||||
|
cbuf_free_chain(t->msg.buffer);
|
||||||
|
release_sem(t->msg.write_sem);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
has_data(thread_id thread)
|
||||||
|
{
|
||||||
|
int32 count;
|
||||||
|
|
||||||
|
if (get_sem_count(thread_get_current_thread()->msg.read_sem, &count) != B_OK)
|
||||||
|
return false;
|
||||||
|
return (count == 0 ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
user_get_thread_info(thread_id id, thread_info *info)
|
user_get_thread_info(thread_id id, thread_info *info)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -196,11 +196,11 @@ thread_id find_thread(const char *name);
|
|||||||
#define get_team_usage_info(tmid, who, info) _get_team_usage_info((tmid), (who), (info), sizeof(*(info)))
|
#define get_team_usage_info(tmid, who, info) _get_team_usage_info((tmid), (who), (info), sizeof(*(info)))
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TO DO
|
// OK
|
||||||
status_t send_data(thread_id thread, int32 code, const void *buf, size_t buffer_size);
|
status_t send_data(thread_id thread, int32 code, const void *buf, size_t buffer_size);
|
||||||
// TO DO
|
// OK
|
||||||
status_t receive_data(thread_id *sender, void *buf, size_t buffer_size);
|
status_t receive_data(thread_id *sender, void *buf, size_t buffer_size);
|
||||||
// TO DO
|
// OK
|
||||||
bool has_data(thread_id thread);
|
bool has_data(thread_id thread);
|
||||||
// TO DO
|
// TO DO
|
||||||
status_t snooze(bigtime_t microseconds);
|
status_t snooze(bigtime_t microseconds);
|
||||||
|
|||||||
Reference in New Issue
Block a user