home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 52
/
Amiga_Dream_52.iso
/
RiscOS
/
APP
/
DEVS
/
LIB
/
THREAD.ZIP
/
Thread
/
ThreadLib
/
c
/
VecKludge
Wrap
Text File
|
1996-12-05
|
4KB
|
137 lines
/* Simtec RiscOS Multithreading Support Code
* (c) 1996 Neil A Carson / Simtec Electronics
*
* Routines to kludge the SharedCLibrary vectors to stop reentrancy problems
*/
#pragma no_check_stack
#include <stdlib.h>
#include "kernel.h"
#include "thread.h"
/* We declare this here because it is not mentioned in any of the standard
* headers (I don't think)
*/
extern int *SIMTEC_x_stack_overflow;
/* This is the semaphore that we use to enforce mutual exclusion
*/
thread_semaphore sem;
/* Some general defines
*/
#define PIPELINE 8 /* pc offset due to pipelining */
#define BRANCH 0xEA000000 /* B instruction */
#define BRANCH_MASK 0x00FFFFFF /* Address mask for B instruction */
#define OS_SynchroniseCodeAreas 0x6E /* A SWI number */
/* Branch to some assembler at a given address, returning an R0 value
*/
extern int thread_branch_to(int r0, int r1, int r2, int addr);
/* My version of malloc()
*/
unsigned real_malloc_addr;
void *unreal_malloc(size_t size)
{
int stasking, result;
thread_get_context(NULL, (thread_context **) &stasking);
if (stasking == 0) thread_wait(&sem, NULL);
result = thread_branch_to(size, 0, 0, real_malloc_addr);
if (stasking == 0) thread_signal(&sem);
return (void *) result;
}
/* My version of calloc()
*/
unsigned real_calloc_addr;
void *unreal_calloc(size_t nmemb, size_t size)
{
unsigned stasking, result;
thread_get_context(NULL, (thread_context **) &stasking);
if (stasking == 0) thread_wait(&sem, NULL);
result = thread_branch_to(nmemb, size, 0, real_calloc_addr);
if (stasking == 0) thread_signal(&sem);
return (void *) result;
}
/* My version of realloc()
*/
unsigned real_realloc_addr;
void *unreal_realloc(void *ptr, size_t size)
{
unsigned stasking, result;
thread_get_context(NULL, (thread_context **) &stasking);
if (stasking == 0) thread_wait(&sem, NULL);
thread_branch_to((int) ptr, size, 0, real_realloc_addr);
if (stasking == 0) thread_signal(&sem);
return (void *) result;
}
/* My version of free()
*/
unsigned real_free_addr;
void unreal_free(size_t size)
{
unsigned stasking;
thread_get_context(NULL, (thread_context **) &stasking);
if (stasking == 0) thread_wait(&sem, NULL);
thread_branch_to(size, 0, 0, real_free_addr); /* Ignore result */
if (stasking == 0) thread_signal(&sem);
}
/* My version of x$stackoverflow
*/
unsigned real_stkovf_addr;
void unreal_stkovf(size_t size)
{
unsigned stasking;
thread_get_context(NULL, (thread_context **) &stasking);
if (stasking == 0) thread_wait(&sem, NULL);
thread_branch_to(size, 0, 0, *SIMTEC_x_stack_overflow);
if (stasking == 0) thread_signal(&sem);
}
/* Claim a vector, storing the old address somewhere.
*/
void thread_claim_vector(unsigned *vec, unsigned *old_addr, unsigned *new_addr)
{
*old_addr = (int) vec + ((*vec & BRANCH_MASK) << 2) + PIPELINE;
*vec = ((((int) new_addr - (int) vec - PIPELINE) >> 2) & BRANCH_MASK)
| BRANCH;
}
/* Do the actual kludges. If people are being sensible, there is no real reason
* why we would want to reverse these kludges, so a function is not supplied to
* do so.
*/
void thread_kludge(void)
{
_kernel_swi_regs r;
thread_claim_vector((unsigned *) malloc, (unsigned *) &real_malloc_addr,
(unsigned *) unreal_malloc);
thread_claim_vector((unsigned *) calloc, (unsigned *) &real_calloc_addr,
(unsigned *) unreal_calloc);
thread_claim_vector((unsigned *) realloc, (unsigned *) &real_realloc_addr,
(unsigned *) unreal_realloc);
thread_claim_vector((unsigned *) free, (unsigned *) &real_free_addr,
(unsigned *) unreal_free);
thread_claim_vector((unsigned *) SIMTEC_x_stack_overflow,
(unsigned *) &real_stkovf_addr,
(unsigned *) unreal_stkovf);
thread_init_semaphore(&sem, 1);
/* Now, we (may) need to do an OS_SynchroniseCodeAreas SWI here, if we are
* on a Virtual Harvard machine (ie. StrongARM).
*/
r.r[0] = 0;
_kernel_swi(OS_SynchroniseCodeAreas, &r, &r);
}