blob: 951c6bfddd6c308f44f9ebab47327b75ae60f089 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ADK_INTERNAL
#include "fwk.h"
#include "coop.h"
#define NUM_REGS 10 //r4-r11,sp,pc
typedef struct CoopTask{
uint32_t regs[NUM_REGS];
void* stackPtr;
struct CoopTask* next;
struct CoopTask* prev;
}CoopTask;
CoopTask* cur = 0;
static CoopTask* __attribute__((noinline)) coopSchedule(char taskDied){
CoopTask* next = cur->next;
if(taskDied){ //delete task
if(next == cur){
dbgPrintf("Last task died. Halting.\n");
while(1);
}
if(cur->stackPtr) free(cur->stackPtr);
cur->next->prev = cur->prev;
cur->prev->next = cur->next;
free(cur);
}
cur = next;
return next;
}
static void __attribute__((naked)) __attribute__((noinline)) coopTaskStart(void){
asm(
"mov r0, r5;"
"blx r4;"
"mov r0, #1;"
"bl coopSchedule;"
"ldmia r0, {r4-r12,lr};"
"mov sp, r12;"
"bx lr;"
);
}
static void __attribute__((naked)) __attribute__((noinline)) coopDoYield(CoopTask* curTask){
asm(
"mov r12, sp;"
"stmia r0, {r4-r12,lr};"
"mov r0, #0;"
"bl coopSchedule;"
"ldmia r0, {r4-r12,lr};"
"mov sp, r12;"
"bx lr;"
);
}
int coopInit(void){
CoopTask* task;
task = malloc(sizeof(CoopTask));
if(!task) return 0;
task->next = task;
task->prev = task;
task->stackPtr = 0;
cur = task;
return 1;
}
int coopSpawn(CoopTaskF taskF, void* taskData, uint32_t stackSz){
uint8_t* stack;
CoopTask* task;
stack = malloc(stackSz);
if(!stack) return 0;
task = malloc(sizeof(CoopTask));
if(!task){
free(stack);
return 0;
}
task->stackPtr = stack;
task->regs[0] = (uint32_t)taskF;
task->regs[1] = (uint32_t)taskData;
task->regs[8] = ((uint32_t)(stack + stackSz)) &~ 7;
task->regs[9] = (uint32_t)&coopTaskStart;
task->prev = cur;
task->next = cur->next;
cur->next->prev = task;
cur->next = task;
//these are here so compiler is sure that function is referenced in both variants (cancels a warning)
if(stackSz == 0xFFFFFFFF) coopSchedule(0);
if(stackSz == 0xFFFFFFFE) coopSchedule(1);
return 1;
}
void coopYield(void){
coopDoYield(cur);
}
void sleep(uint32_t ms)
{
uint64_t a = fwkGetUptime();
while (fwkGetUptime() - a < ms)
coopYield();
}