mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-04 17:49:45 +02:00
323 lines
9.6 KiB
C
323 lines
9.6 KiB
C
/* timebase.c -- management of calls, time bases and heaps for moxc */
|
||
|
||
/*****************************************************************************
|
||
* Change Log
|
||
* Date | Change
|
||
*-----------+-----------------------------------------------------------------
|
||
* 2-Apr-91 | JDW : further changes
|
||
* 21-Mar-92 | GWL : abort recovery
|
||
* 28-Apr-03 | DM : true->TRUE
|
||
*****************************************************************************/
|
||
|
||
|
||
#include "stdio.h"
|
||
#include "cext.h"
|
||
#include "userio.h"
|
||
#include "midifns.h"
|
||
#include "timebase.h"
|
||
#include "moxc.h"
|
||
|
||
|
||
timebase_type timebase_queue = NULL; /* waiting to run timebase queue */
|
||
call_type callfree = NULL; /* free list */
|
||
|
||
private void fatal();
|
||
|
||
|
||
/****************************************************************************
|
||
* timebase_create
|
||
* Inputs:
|
||
* maxsize is the initial size of the heap
|
||
* Outputs:
|
||
* returns an initialized timebase_type
|
||
****************************************************************************/
|
||
|
||
timebase_type timebase_create(maxsize)
|
||
int maxsize;
|
||
{
|
||
static char *error_msg = "Out of memory in timebase_create()";
|
||
timebase_type base = (timebase_type) memget(sizeof(timebase_node));
|
||
if (!base) fatal(error_msg);
|
||
base->next = NULL;
|
||
base->next_time = MAXTIME;
|
||
base->virt_base = 0L;
|
||
base->real_base = 0L;
|
||
base->rate = 256L;
|
||
base->heap_size = 0;
|
||
base->heap_max = maxsize;
|
||
base->heap = (call_type *) memget(sizeof(call_type) * maxsize);
|
||
if (!base->heap) fatal(error_msg);
|
||
return base;
|
||
}
|
||
|
||
/****************************************************************************
|
||
* callinsert
|
||
* Inputs:
|
||
* timebase_type base: the time base and heap
|
||
* call_type call: the call to insert in heap
|
||
* Outputs:
|
||
none
|
||
* Implementation:
|
||
* linear insertion; to be changed to heap
|
||
****************************************************************************/
|
||
|
||
void callinsert(base, call)
|
||
timebase_type base;
|
||
call_type call;
|
||
{
|
||
int i;
|
||
register call_type *heap = base->heap;
|
||
|
||
/* handle overflow -- this should never be executed if the user
|
||
* gives the right initial heap size
|
||
*/
|
||
base->heap_size++;
|
||
if (base->heap_size >= base->heap_max) {
|
||
call_type *new_heap = (call_type *)
|
||
memget((base->heap_max << 1) * sizeof(call_type));
|
||
int i;
|
||
call_type *oldptr;
|
||
call_type *newptr;
|
||
if (!new_heap) {
|
||
gprintf(TRANS, "Out of space, can't allocate new heap\n");
|
||
EXIT(1);
|
||
}
|
||
|
||
oldptr = base->heap;
|
||
newptr = new_heap;
|
||
|
||
for (i = base->heap_max; i > 0; i--) *newptr++ = *oldptr++;
|
||
memfree((char *) heap, base->heap_max * sizeof(call_type));
|
||
base->heap = heap = new_heap;
|
||
base->heap_max = (base->heap_max << 1);
|
||
}
|
||
|
||
/* now do the heap insert */
|
||
i = base->heap_size;
|
||
while (i > 1) {
|
||
int parent = i >> 1;
|
||
if (heap[parent]->u.e.time < call->u.e.time ||
|
||
(heap[parent]->u.e.time == call->u.e.time &&
|
||
heap[parent]->u.e.priority <= call->u.e.priority)) break;
|
||
heap[i] = heap[parent];
|
||
i = parent;
|
||
}
|
||
heap[i] = call;
|
||
|
||
/* if next_time might change, reinsert base into queue */
|
||
if (heap[1] == call) {
|
||
remove_base(base);
|
||
insert_base(base);
|
||
}
|
||
}
|
||
|
||
/****************************************************************************
|
||
* callshow
|
||
* Inputs:
|
||
* calltype call: the call to show
|
||
* Effect:
|
||
* prints a description of call
|
||
* Assumes:
|
||
* call is not null
|
||
****************************************************************************/
|
||
void callshow(call)
|
||
call_type call;
|
||
{
|
||
int i;
|
||
gprintf(TRANS,"address: %lx\n", (ulong)call);
|
||
gprintf(TRANS,"time: %ld\n", call->u.e.time);
|
||
gprintf(TRANS,"routine: %lx\n", (ulong)call->u.e.routine);
|
||
gprintf(TRANS,"parameters:");
|
||
for (i = 0; i < MAX_CALL_ARGS; i++) {
|
||
gprintf(TRANS, " %d", call->u.e.p.arg[i]);
|
||
}
|
||
gprintf(TRANS, "\n");
|
||
}
|
||
|
||
/***************************************************************
|
||
* fatal
|
||
*
|
||
* Input : msg: a message to be displayed
|
||
* Effect: print message and exit program
|
||
***************************************************************/
|
||
|
||
private void fatal(msg)
|
||
char *msg;
|
||
{
|
||
gprintf(FATAL, msg);
|
||
EXIT(1);
|
||
}
|
||
|
||
/***************************************************************
|
||
* timebase_free
|
||
*
|
||
* Input : a time base
|
||
* Effect: deallocate the time base
|
||
***************************************************************/
|
||
|
||
void timebase_free(timebase)
|
||
timebase_type timebase;
|
||
{
|
||
remove_base(timebase);
|
||
if (timebase->heap) {
|
||
memfree((char *) timebase->heap,
|
||
(timebase->heap_max * sizeof(call_type)));
|
||
}
|
||
memfree((char *) timebase, sizeof(timebase_node));
|
||
}
|
||
|
||
/***************************************************************
|
||
* insert_base
|
||
*
|
||
* Input : a time base not in the list
|
||
* Effect: insert timebase at the appropriate spot in the list
|
||
* computes the next_time field from the top of the heap
|
||
***************************************************************/
|
||
|
||
void insert_base(timebase)
|
||
timebase_type timebase;
|
||
{
|
||
register timebase_type *ptr = &timebase_queue;
|
||
register time_type next_time = MAXTIME;
|
||
/* compute next_time */
|
||
if (timebase->heap_size != 0) {
|
||
register call_type call = timebase->heap[1];
|
||
/* virt to real calculation */
|
||
next_time = (virt_to_real_256(timebase, call->u.e.time) &
|
||
0xFFFFFF00) + call->u.e.priority;
|
||
/* gprintf(TRANS,
|
||
"insert next_time is %ld, vt %ld, rb %ld, vb %ld rt %ld\n",
|
||
next_time, timebase->heap[1]->u.e.time,
|
||
timebase->real_base, timebase->virt_base, timebase->rate);
|
||
*/
|
||
}
|
||
timebase->next_time = next_time;
|
||
|
||
if (next_time != MAXTIME) {
|
||
/* insert into the list */
|
||
while (TRUE) {
|
||
if (! *ptr) {
|
||
*ptr = timebase;
|
||
timebase->next = NULL;
|
||
return;
|
||
} else if ((*ptr)->next_time >= next_time) {
|
||
timebase->next = *ptr;
|
||
*ptr = timebase;
|
||
return;
|
||
} else ptr = &((*ptr)->next);
|
||
}
|
||
}
|
||
}
|
||
|
||
/***************************************************************
|
||
* remove_base
|
||
*
|
||
* Input : timebase
|
||
* Effect: if timebase is in the queue, remove it
|
||
***************************************************************/
|
||
|
||
void remove_base(timebase)
|
||
timebase_type timebase;
|
||
{
|
||
timebase_type *ptr = &timebase_queue;
|
||
while (*ptr) {
|
||
if (*ptr == timebase) {
|
||
*ptr = timebase->next;
|
||
return;
|
||
} else ptr = &((*ptr)->next);
|
||
}
|
||
}
|
||
|
||
/***************************************************************
|
||
* remove_call
|
||
*
|
||
* Input : a timebase -- passed as a global
|
||
* Assumes: a_timebase->heap_size > 0
|
||
* Returns: the earliest call in the queue
|
||
* Effect: removes the earliest call in the queue
|
||
***************************************************************/
|
||
|
||
call_type remove_call(timebase_type a_timebase)
|
||
{
|
||
register call_type *heap = a_timebase->heap;
|
||
call_type result = heap[1];
|
||
register call_type large;
|
||
int i = 1;
|
||
int child = i << 1;;
|
||
large = heap[a_timebase->heap_size--];
|
||
while (child <= a_timebase->heap_size) {
|
||
if (child + 1 <= a_timebase->heap_size) {
|
||
if (heap[child + 1]->u.e.time < heap[child]->u.e.time ||
|
||
(heap[child + 1]->u.e.time == heap[child]->u.e.time &&
|
||
heap[child + 1]->u.e.priority < heap[child]->u.e.priority))
|
||
child++;
|
||
}
|
||
/* child is now the index of the least child */
|
||
if (large->u.e.time < heap[child]->u.e.time ||
|
||
(large->u.e.time == heap[child]->u.e.time &&
|
||
large->u.e.priority <= heap[child]->u.e.priority)) break;
|
||
/* swap */
|
||
heap[i] = heap[child];
|
||
i = child;
|
||
child = i << 1;
|
||
}
|
||
heap[i] = large;
|
||
return result;
|
||
}
|
||
|
||
/***************************************************************
|
||
* set_rate
|
||
*
|
||
* Input : timebase and new rate
|
||
* Effect: makes the current rate of timebase be rate
|
||
***************************************************************/
|
||
|
||
void set_rate(base, rate)
|
||
timebase_type base;
|
||
time_type rate;
|
||
{
|
||
if (base == timebase) base->virt_base = virttime;
|
||
else base->virt_base = real_to_virt(base, eventtime);
|
||
base->real_base = eventtime;
|
||
base->rate = rate;
|
||
/* gprintf(TRANS, "new real_base %ld virt_base %ld\n",
|
||
base->real_base, base->virt_base);
|
||
*/
|
||
remove_base(base);
|
||
insert_base(base);
|
||
}
|
||
|
||
/***************************************************************
|
||
* set_virttime
|
||
*
|
||
* Input : virtual time
|
||
* Effect: makes the current virtual time of timebase be vtime
|
||
***************************************************************/
|
||
|
||
void set_virttime(base, vtime)
|
||
timebase_type base;
|
||
time_type vtime;
|
||
{
|
||
base->real_base = eventtime;
|
||
base->virt_base = vtime;
|
||
if (base == timebase) virttime = vtime;
|
||
remove_base(base);
|
||
insert_base(base);
|
||
}
|
||
|
||
/***************************************************************
|
||
* timebase_use
|
||
*
|
||
* Input : a timebase to use for scheduling
|
||
* Effect: sets up globals: timebase, virttime
|
||
***************************************************************/
|
||
|
||
void timebase_use(base)
|
||
register timebase_type base;
|
||
{
|
||
if (timebase != base) {
|
||
timebase = base;
|
||
virttime = real_to_virt(base, eventtime);
|
||
}
|
||
}
|