mirror of
https://github.com/drasko/codezero.git
synced 2026-04-04 19:19:03 +02:00
Mutex test progress
- Mutex test added. Forked tasks demonstrate produce/consumer using a shared mmap'ed page. - Added l4lib assembler syscall - Added forgotten SWI to mutex control offset in syscall page. - Added mutex head initialization - Contended child successfully sleeps in a waitqueue. Issues: - Somehow the child's produced page buffer is altered at about [4020] offset. Parent fails to validate buffer therefore. - Need to add syncing to test so that parent does not unlock and lock again before child has a chance to lock buffer and produce.
This commit is contained in:
@@ -6,6 +6,8 @@
|
|||||||
#if defined (__KERNEL__)
|
#if defined (__KERNEL__)
|
||||||
#define MUTEX_CONTROL_LOCK L4_MUTEX_LOCK
|
#define MUTEX_CONTROL_LOCK L4_MUTEX_LOCK
|
||||||
#define MUTEX_CONTROL_UNLOCK L4_MUTEX_UNLOCK
|
#define MUTEX_CONTROL_UNLOCK L4_MUTEX_UNLOCK
|
||||||
|
|
||||||
|
void init_mutex_queue_head(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define L4_MUTEX_LOCK 0
|
#define L4_MUTEX_LOCK 0
|
||||||
|
|||||||
@@ -24,23 +24,29 @@ struct mutex_queue {
|
|||||||
|
|
||||||
struct mutex_queue_head {
|
struct mutex_queue_head {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock for mutex_queue create/deletion and also list add/removal.
|
||||||
|
* Both operations are done jointly so a single lock is enough.
|
||||||
|
*/
|
||||||
|
struct mutex mutex_control_mutex;
|
||||||
int count;
|
int count;
|
||||||
} mutex_queue_head;
|
} mutex_queue_head;
|
||||||
|
|
||||||
/*
|
void init_mutex_queue_head(void)
|
||||||
* Lock for mutex_queue create/deletion and also list add/removal.
|
{
|
||||||
* Both operations are done jointly so a single lock is enough.
|
memset(&mutex_queue_head, 0, sizeof (mutex_queue_head));
|
||||||
*/
|
INIT_LIST_HEAD(&mutex_queue_head.list);
|
||||||
struct mutex mutex_control_mutex;
|
mutex_init(&mutex_queue_head.mutex_control_mutex);
|
||||||
|
}
|
||||||
void mutex_queue_head_lock()
|
void mutex_queue_head_lock()
|
||||||
{
|
{
|
||||||
mutex_lock(&mutex_control_mutex);
|
mutex_lock(&mutex_queue_head.mutex_control_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_queue_head_unlock()
|
void mutex_queue_head_unlock()
|
||||||
{
|
{
|
||||||
mutex_unlock(&mutex_control_mutex);
|
mutex_unlock(&mutex_queue_head.mutex_control_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,5 +30,6 @@ BEGIN_PROC(arm_system_calls)
|
|||||||
swi 0x14 @ kread /* 0x28 */
|
swi 0x14 @ kread /* 0x28 */
|
||||||
swi 0x14 @ kmem_control /* 0x2C */
|
swi 0x14 @ kmem_control /* 0x2C */
|
||||||
swi 0x14 @ time /* 0x30 */
|
swi 0x14 @ time /* 0x30 */
|
||||||
|
swi 0x14 @ mutex_control /* 0x34 */
|
||||||
END_PROC(arm_system_calls)
|
END_PROC(arm_system_calls)
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include INC_PLAT(printascii.h)
|
#include INC_PLAT(printascii.h)
|
||||||
#include INC_API(syscall.h)
|
#include INC_API(syscall.h)
|
||||||
#include INC_API(kip.h)
|
#include INC_API(kip.h)
|
||||||
|
#include INC_API(mutex.h)
|
||||||
|
|
||||||
unsigned int kernel_mapping_end;
|
unsigned int kernel_mapping_end;
|
||||||
|
|
||||||
@@ -344,6 +345,7 @@ void init_tasks()
|
|||||||
/* Initialise the global task and address space lists */
|
/* Initialise the global task and address space lists */
|
||||||
init_ktcb_list();
|
init_ktcb_list();
|
||||||
init_address_space_list();
|
init_address_space_list();
|
||||||
|
init_mutex_queue_head();
|
||||||
|
|
||||||
printk("%s: Initialized. Starting %s as pager.\n",
|
printk("%s: Initialized. Starting %s as pager.\n",
|
||||||
__KERNELNAME__, __PAGERNAME__);
|
__KERNELNAME__, __PAGERNAME__);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ void syscall_init()
|
|||||||
syscall_table[sys_kread_offset >> 2] = (syscall_fn_t)sys_kread;
|
syscall_table[sys_kread_offset >> 2] = (syscall_fn_t)sys_kread;
|
||||||
syscall_table[sys_kmem_control_offset >> 2] = (syscall_fn_t)sys_kmem_control;
|
syscall_table[sys_kmem_control_offset >> 2] = (syscall_fn_t)sys_kmem_control;
|
||||||
syscall_table[sys_time_offset >> 2] = (syscall_fn_t)sys_time;
|
syscall_table[sys_time_offset >> 2] = (syscall_fn_t)sys_time;
|
||||||
syscall_table[sys_mutex_control_offset >> 2] = (syscall_fn_t)sys_mutex_control;
|
syscall_table[sys_mutex_control_offset >> 2] = (syscall_fn_t)sys_mutex_control;
|
||||||
|
|
||||||
add_mapping(virt_to_phys(&__syscall_page_start),
|
add_mapping(virt_to_phys(&__syscall_page_start),
|
||||||
ARM_SYSCALL_PAGE, PAGE_SIZE, MAP_USR_RO_FLAGS);
|
ARM_SYSCALL_PAGE, PAGE_SIZE, MAP_USR_RO_FLAGS);
|
||||||
|
|||||||
@@ -197,6 +197,18 @@ BEGIN_PROC(l4_space_control)
|
|||||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||||
END_PROC(l4_space_control)
|
END_PROC(l4_space_control)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Locks/unlocks a userspace mutex.
|
||||||
|
* @r0 = mutex virtual address, @r1 = mutex operation code
|
||||||
|
*/
|
||||||
|
BEGIN_PROC(l4_mutex_control)
|
||||||
|
stmfd sp!, {lr}
|
||||||
|
ldr r12, =__l4_mutex_control
|
||||||
|
mov lr, pc
|
||||||
|
ldr pc, [r12]
|
||||||
|
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||||
|
END_PROC(l4_mutex_control)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets registers of a thread and its pager.
|
* Sets registers of a thread and its pager.
|
||||||
* @r0 = ptr to exregs_data structure, @r1 = tid of thread.
|
* @r0 = ptr to exregs_data structure, @r1 = tid of thread.
|
||||||
|
|||||||
@@ -55,6 +55,6 @@ void __l4_init(void)
|
|||||||
(__l4_exchange_registers_t)kip->exchange_registers;
|
(__l4_exchange_registers_t)kip->exchange_registers;
|
||||||
__l4_kmem_control = (__l4_kmem_control_t)kip->kmem_control;
|
__l4_kmem_control = (__l4_kmem_control_t)kip->kmem_control;
|
||||||
__l4_time = (__l4_time_t)kip->time;
|
__l4_time = (__l4_time_t)kip->time;
|
||||||
__l4_mutex_control= (__l4_mutex_control_t)kip->mutex_control;
|
__l4_mutex_control = (__l4_mutex_control_t)kip->mutex_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <l4lib/mutex.h>
|
#include <l4lib/mutex.h>
|
||||||
#include <l4lib/types.h>
|
#include <l4lib/types.h>
|
||||||
#include <l4lib/arch/syscalls.h>
|
#include <l4lib/arch/syscalls.h>
|
||||||
|
#include <l4lib/arch/syslib.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTES:
|
* NOTES:
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ int dirtest(void);
|
|||||||
int fileio(void);
|
int fileio(void);
|
||||||
int clonetest(void);
|
int clonetest(void);
|
||||||
int exectest(void);
|
int exectest(void);
|
||||||
|
int user_mutex_test(void);
|
||||||
|
|
||||||
#endif /* __TEST0_TESTS_H__ */
|
#endif /* __TEST0_TESTS_H__ */
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ void main(void)
|
|||||||
ipc_full_test();
|
ipc_full_test();
|
||||||
ipc_extended_test();
|
ipc_extended_test();
|
||||||
}
|
}
|
||||||
|
if (parent_of_all == getpid()) {
|
||||||
|
user_mutex_test();
|
||||||
|
}
|
||||||
exectest();
|
exectest();
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
|
|||||||
161
tasks/test0/src/mutextest.c
Normal file
161
tasks/test0/src/mutextest.c
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Tests for userspace mutexes
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||||
|
*/
|
||||||
|
#include <l4lib/arch/syslib.h>
|
||||||
|
#include <l4lib/ipcdefs.h>
|
||||||
|
#include <l4lib/mutex.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <tests.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This structure is placed at the head of shared memory.
|
||||||
|
* Tasks lock and write to rest of the page. Indicate that
|
||||||
|
* they have run, and the later running task tests that both
|
||||||
|
* processes has run and no data corruption occured on page_rest.
|
||||||
|
*/
|
||||||
|
struct shared_page {
|
||||||
|
struct l4_mutex mutex;
|
||||||
|
int child_has_run;
|
||||||
|
int parent_has_run;
|
||||||
|
char page_rest[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct shared_page *shared_page;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test forks a parent task, creates a shared memory mapping, and makes two tasks
|
||||||
|
* lock and write to almost the whole page 10 times with different values, and makes
|
||||||
|
* the tasks test that the writes are all there without any wrong values. The amount of
|
||||||
|
* time spent should justify a context switch and demonstrate that lock protects the
|
||||||
|
* region.
|
||||||
|
*/
|
||||||
|
int user_mutex_test(void)
|
||||||
|
{
|
||||||
|
pid_t child, parent;
|
||||||
|
int map_size = PAGE_SIZE;
|
||||||
|
int buf_size;
|
||||||
|
void *base;
|
||||||
|
|
||||||
|
/* Get parent pid */
|
||||||
|
parent = getpid();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a shared anonymous memory region. This can be
|
||||||
|
* accessed by both parent and child after a fork.
|
||||||
|
*/
|
||||||
|
if ((int)(base = mmap(0, map_size, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED | MAP_ANONYMOUS, 0, 0)) < 0) {
|
||||||
|
printf("%s: mmap for extended ipc buffer failed: %d\n",
|
||||||
|
__FUNCTION__, (int)base);
|
||||||
|
goto out_err;
|
||||||
|
} else
|
||||||
|
printf("mmap: Anonymous shared buffer at %p\n", base);
|
||||||
|
|
||||||
|
shared_page = base;
|
||||||
|
|
||||||
|
/* Find the buffer size */
|
||||||
|
buf_size = map_size - sizeof(*shared_page);
|
||||||
|
printf("Total buffer size: %d\n", buf_size);
|
||||||
|
|
||||||
|
/* Initialize the mutex */
|
||||||
|
l4_mutex_init(&shared_page->mutex);
|
||||||
|
|
||||||
|
/* Initialize buffer with unique child value */
|
||||||
|
printf("Child writing:\n");
|
||||||
|
for (int i = 0; i < buf_size; i++) {
|
||||||
|
shared_page->page_rest[i] = 'c';
|
||||||
|
printf("%c", shared_page->page_rest[i]);
|
||||||
|
}
|
||||||
|
printf("\n\n");
|
||||||
|
|
||||||
|
/* Fork the current task */
|
||||||
|
if ((child = fork()) < 0) {
|
||||||
|
printf("%s: Fork failed with %d\n", __FUNCTION__, errno);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
printf("%d: Created child with pid %d\n", getpid(), child);
|
||||||
|
else
|
||||||
|
printf("Child %d running.\n", getpid());
|
||||||
|
|
||||||
|
/* Child locks and produces */
|
||||||
|
if (child == 0) {
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
/* Lock */
|
||||||
|
printf("Child locking page.\n");
|
||||||
|
l4_mutex_lock(&shared_page->mutex);
|
||||||
|
|
||||||
|
printf("Child locked page.\n");
|
||||||
|
/* Get sample value */
|
||||||
|
char val = shared_page->page_rest[0];
|
||||||
|
|
||||||
|
/* Write a unique child value to whole buffer */
|
||||||
|
for (int i = 0; i < buf_size; i++) {
|
||||||
|
/* Check sample is same in all */
|
||||||
|
if (shared_page->page_rest[i] != val) {
|
||||||
|
printf("Sample values dont match. "
|
||||||
|
"page_rest[%d] = %c, "
|
||||||
|
"val = %c\n", i,
|
||||||
|
shared_page->page_rest[i], val);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
shared_page->page_rest[i] = 'c';
|
||||||
|
}
|
||||||
|
printf("Child produced.\n");
|
||||||
|
/* Unlock */
|
||||||
|
l4_mutex_unlock(&shared_page->mutex);
|
||||||
|
printf("Child unlocked page.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parent locks and consumes */
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
printf("Parent locking page.\n");
|
||||||
|
|
||||||
|
/* Lock the page */
|
||||||
|
l4_mutex_lock(&shared_page->mutex);
|
||||||
|
printf("Parent locked page.\n");
|
||||||
|
|
||||||
|
printf("Parent reading:\n");
|
||||||
|
|
||||||
|
/* Test and consume the page */
|
||||||
|
for (int i = 0; i < buf_size; i++) {
|
||||||
|
printf("%c", shared_page->page_rest[i]);
|
||||||
|
/* Test that child has produced */
|
||||||
|
if (shared_page->page_rest[i] != 'c') {
|
||||||
|
printf("Child not produced. "
|
||||||
|
"page_rest[%d] = %c, "
|
||||||
|
"expected = 'c'\n",
|
||||||
|
i, shared_page->page_rest[i]);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
/* Consume the page */
|
||||||
|
shared_page->page_rest[i] = 'P';
|
||||||
|
}
|
||||||
|
printf("\n\n");
|
||||||
|
printf("Parent consumed.\n");
|
||||||
|
l4_mutex_unlock(&shared_page->mutex);
|
||||||
|
printf("Parent unlocked page.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("USER MUTEX TEST: -- PASSED --\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_err:
|
||||||
|
printf("USER MUTEX TEST: -- FAILED --\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user