Cooperative multitasking added.
This commit is contained in:
parent
f507b0713b
commit
07dbada6e8
7 changed files with 323 additions and 24 deletions
|
@ -44,6 +44,7 @@ INCLUDEPATH += \
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
$$LINUX_HEADERS \
|
$$LINUX_HEADERS \
|
||||||
src/gui/button.h \
|
src/gui/button.h \
|
||||||
|
src/gui/task.h \
|
||||||
src/thirdparty/stb_ds.h \
|
src/thirdparty/stb_ds.h \
|
||||||
src/thirdparty/stb_leakcheck.h \
|
src/thirdparty/stb_leakcheck.h \
|
||||||
src/thirdparty/stb_image.h \
|
src/thirdparty/stb_image.h \
|
||||||
|
@ -67,6 +68,7 @@ SOURCES = \
|
||||||
src/gui/font.c \
|
src/gui/font.c \
|
||||||
src/gui/desktop.c \
|
src/gui/desktop.c \
|
||||||
src/gui/gui.c \
|
src/gui/gui.c \
|
||||||
|
src/gui/task.c \
|
||||||
src/gui/widget.c \
|
src/gui/widget.c \
|
||||||
src/gui/window.c \
|
src/gui/window.c \
|
||||||
src/gui/image.c \
|
src/gui/image.c \
|
||||||
|
|
|
@ -377,7 +377,7 @@ static uint8_t vbeIsDesiredMode(void) {
|
||||||
// Packed or Direct Color mode.
|
// Packed or Direct Color mode.
|
||||||
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED || _vbeModeInfo.memoryModel == VBE_MM_DCOLOR) {
|
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED || _vbeModeInfo.memoryModel == VBE_MM_DCOLOR) {
|
||||||
// Resolution minimum of 640x480.
|
// Resolution minimum of 640x480.
|
||||||
if (_vbeModeInfo.xResolution >= 640 && _vbeModeInfo.yResolution >= 480) {
|
if (_vbeModeInfo.xResolution >= 800 && _vbeModeInfo.yResolution >= 600) {
|
||||||
// Multiple of 8
|
// Multiple of 8
|
||||||
if (DIVISIBLE_BY_EIGHT(_vbeModeInfo.xResolution) && DIVISIBLE_BY_EIGHT(_vbeModeInfo.yResolution)) {
|
if (DIVISIBLE_BY_EIGHT(_vbeModeInfo.xResolution) && DIVISIBLE_BY_EIGHT(_vbeModeInfo.yResolution)) {
|
||||||
// Valid mode!
|
// Valid mode!
|
||||||
|
@ -601,8 +601,8 @@ uint16_t vbeSetScanlineLength(uint16_t pixelLength) {
|
||||||
r.x.bx = 0x0000;
|
r.x.bx = 0x0000;
|
||||||
r.x.cx = pixelLength;
|
r.x.cx = pixelLength;
|
||||||
__dpmi_int(0x10, &r);
|
__dpmi_int(0x10, &r);
|
||||||
if(r.h.ah != 0) return(0);
|
if (r.h.ah != 0) return(0);
|
||||||
if(r.x.cx != pixelLength) return(0);
|
if (r.x.cx != pixelLength) return(0);
|
||||||
|
|
||||||
_vbeSurface.virtualXResolution = pixelLength;
|
_vbeSurface.virtualXResolution = pixelLength;
|
||||||
|
|
||||||
|
@ -615,11 +615,11 @@ int16_t vbeShowInfo(void) {
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8
|
// 0 1 2 3 4 5 6 7 8
|
||||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
printf("VBE 2.0 driver v1.0 (c) 2021, Scott Duensing <scott@kangaroopunch.com>\n");
|
//printf("VBE 2.0 driver v1.0 (c) 2021, Scott Duensing <scott@kangaroopunch.com>\n");
|
||||||
printf("Based on: VBE 2.0 driver v1.0 (c) 1999, Tobias Koch <tobias.koch@gmail.com>\n\n");
|
//printf("Based on: VBE 2.0 driver v1.0 (c) 1999, Tobias Koch <tobias.koch@gmail.com>\n\n");
|
||||||
|
|
||||||
if (vbeGetInfo() == NULL) {
|
if (vbeGetInfo() == NULL) {
|
||||||
printf("No VESA BIOS Extensions found.\n\n");
|
printf("No VESA BIOS Extensions found.\n");
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
printf(
|
printf(
|
||||||
|
@ -643,7 +643,7 @@ int16_t vbeShowInfo(void) {
|
||||||
_vbeInfo.oemProductRevPtr,
|
_vbeInfo.oemProductRevPtr,
|
||||||
vbeGetPmodeInterface() ? "Found" : "Missing");
|
vbeGetPmodeInterface() ? "Found" : "Missing");
|
||||||
} else {
|
} else {
|
||||||
printf("VESA BIOS Extension 2.0 or better required!\n\n");
|
printf("VESA BIOS Extension 2.0 or better required!\n");
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Inspired by https://github.com/JMarlin/wsbe
|
||||||
|
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
|
|
|
@ -22,9 +22,6 @@
|
||||||
#define GUI_H
|
#define GUI_H
|
||||||
|
|
||||||
|
|
||||||
// Inspired by https://github.com/JMarlin/wsbe
|
|
||||||
|
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "vesa.h"
|
#include "vesa.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|
222
client/src/gui/task.c
Normal file
222
client/src/gui/task.c
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
/*
|
||||||
|
* Kangaroo Punch Multi Player Game Server Mark II
|
||||||
|
* Copyright (C) 2020-2021 Scott Duensing
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Based on https://brennan.io/2020/05/24/userspace-cooperative-multitasking/
|
||||||
|
|
||||||
|
|
||||||
|
// https://sourceforge.net/p/predef/wiki/Home/
|
||||||
|
#if !defined(__i386__) && !defined(__i486__) && !defined(__i586__) && !defined(__i686__) && !defined(__x86_64__)
|
||||||
|
#error "Only Intel 386 and later processors are supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__DJGPP__) && !defined(__GNUC__)
|
||||||
|
#error "Requires GCC or DJGPP."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct TaskS {
|
||||||
|
enum {
|
||||||
|
STATE_CREATED,
|
||||||
|
STATE_RUNNING,
|
||||||
|
STATE_WAITING
|
||||||
|
} status;
|
||||||
|
uint32_t id;
|
||||||
|
jmp_buf buf;
|
||||||
|
void (*function)(void *);
|
||||||
|
void *data;
|
||||||
|
void *stackBottom;
|
||||||
|
void *stackTop;
|
||||||
|
uint32_t stackSize;
|
||||||
|
} TaskT;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INIT = 0,
|
||||||
|
SCHEDULE,
|
||||||
|
EXIT_TASK,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct PrivateS {
|
||||||
|
jmp_buf buf;
|
||||||
|
TaskT *current;
|
||||||
|
TaskT **taskList;
|
||||||
|
} PrivateT;
|
||||||
|
|
||||||
|
|
||||||
|
static PrivateT _private;
|
||||||
|
static uint16_t _stackSizeInK;
|
||||||
|
|
||||||
|
|
||||||
|
static TaskT *taskChoose(void);
|
||||||
|
static void taskFree(void);
|
||||||
|
static void taskSchedule(void);
|
||||||
|
|
||||||
|
|
||||||
|
static TaskT *taskChoose(void) {
|
||||||
|
TaskT *task = NULL;
|
||||||
|
uint32_t len = arrlenu(_private.taskList);
|
||||||
|
uint32_t x;
|
||||||
|
|
||||||
|
// Find the next task to run.
|
||||||
|
for (x=0; x<len; x++) {
|
||||||
|
task = _private.taskList[x];
|
||||||
|
if (task->status == STATE_CREATED || task->status == STATE_RUNNING) {
|
||||||
|
// Move it to the end of the list.
|
||||||
|
arrdel(_private.taskList, x);
|
||||||
|
arrput(_private.taskList, task);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void taskCreate(void (*function)(void *), void *data) {
|
||||||
|
static uint32_t id = 1;
|
||||||
|
TaskT *task = (TaskT *)malloc(sizeof(TaskT));
|
||||||
|
|
||||||
|
task->status = STATE_CREATED;
|
||||||
|
task->function = function;
|
||||||
|
task->data = data;
|
||||||
|
task->id = id++;
|
||||||
|
task->stackSize = _stackSizeInK * 1024;
|
||||||
|
task->stackBottom = malloc(task->stackSize);
|
||||||
|
task->stackTop = task->stackBottom + task->stackSize;
|
||||||
|
|
||||||
|
arrput(_private.taskList, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void taskExit(void) {
|
||||||
|
TaskT *task = _private.current;
|
||||||
|
uint32_t len = arrlenu(_private.taskList);
|
||||||
|
uint32_t x;
|
||||||
|
|
||||||
|
// Find our task.
|
||||||
|
for (x=0; x<len; x++) {
|
||||||
|
if (task == _private.taskList[x]) {
|
||||||
|
// Remove us from the list.
|
||||||
|
arrdel(_private.taskList, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't free the task or we won't have a stack.
|
||||||
|
// Defer until we longjmp back into the old stack.
|
||||||
|
longjmp(_private.buf, EXIT_TASK);
|
||||||
|
|
||||||
|
// Execution doesn't get to here.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void taskFree(void) {
|
||||||
|
TaskT *task = _private.current;
|
||||||
|
|
||||||
|
_private.current = NULL;
|
||||||
|
free(task->stackBottom);
|
||||||
|
free(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
|
void taskRun(void) {
|
||||||
|
// This is the exit path for the scheduler!
|
||||||
|
switch (setjmp(_private.buf)) {
|
||||||
|
case EXIT_TASK:
|
||||||
|
taskFree();
|
||||||
|
|
||||||
|
case INIT:
|
||||||
|
case SCHEDULE:
|
||||||
|
taskSchedule();
|
||||||
|
// If we get here, there's nothing else to do so exit
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Task scheduler error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|
||||||
|
static void taskSchedule(void) {
|
||||||
|
TaskT *next = taskChoose();
|
||||||
|
|
||||||
|
if (!next) return;
|
||||||
|
|
||||||
|
_private.current = next;
|
||||||
|
|
||||||
|
if (next->status == STATE_CREATED) {
|
||||||
|
// This task has not been started yet.
|
||||||
|
// Assign a new stack pointer, run the task, and exit it at the end.
|
||||||
|
register void *top = next->stackTop;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
// 64 bit.
|
||||||
|
asm volatile(
|
||||||
|
"mov %[rs], %%rsp \n"
|
||||||
|
: [ rs ] "+r" (top) ::
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
// 32 bit.
|
||||||
|
asm volatile(
|
||||||
|
"mov %[rs], %%esp \n"
|
||||||
|
: [ rs ] "+r" (top) ::
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
// Run the task.
|
||||||
|
next->status = STATE_RUNNING;
|
||||||
|
next->function(next->data);
|
||||||
|
|
||||||
|
// The stack pointer should be back where we set it. Returning would be a very, very bad idea. Let's instead exit.
|
||||||
|
taskExit();
|
||||||
|
} else {
|
||||||
|
longjmp(next->buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execution doesn't get to here.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void taskShutdown(void) {
|
||||||
|
// Nothing yet.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void taskStartup(uint16_t stackInK) {
|
||||||
|
_stackSizeInK = stackInK;
|
||||||
|
_private.current = NULL;
|
||||||
|
_private.taskList = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void taskYield(void) {
|
||||||
|
if (setjmp(_private.current->buf)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
longjmp(_private.buf, SCHEDULE);
|
||||||
|
}
|
||||||
|
}
|
36
client/src/gui/task.h
Normal file
36
client/src/gui/task.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Kangaroo Punch Multi Player Game Server Mark II
|
||||||
|
* Copyright (C) 2020-2021 Scott Duensing
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TASK_H
|
||||||
|
#define TASK_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
|
||||||
|
void taskCreate(void (*function)(void *), void *data);
|
||||||
|
void taskExit(void);
|
||||||
|
void taskRun(void);
|
||||||
|
void taskShutdown(void);
|
||||||
|
void taskStartup(uint16_t stackInK);
|
||||||
|
void taskYield(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TASK_H
|
|
@ -18,8 +18,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
#include "vesa.h"
|
#include "vesa.h"
|
||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
|
#include "task.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
@ -34,19 +36,17 @@ void buttonClick(WidgetT *widget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void test(void) {
|
void test(void *data) {
|
||||||
MouseT *mouse = NULL;
|
MouseT *mouse = NULL;
|
||||||
ImageT *pointer = NULL;
|
ImageT *pointer = NULL;
|
||||||
PixelT alpha;
|
PixelT alpha;
|
||||||
DesktopT *desktop = NULL;
|
DesktopT *desktop = (DesktopT *)guiRootGet();
|
||||||
WindowT *w1 = NULL;
|
WindowT *w1 = NULL;
|
||||||
WindowT *w2 = NULL;
|
WindowT *w2 = NULL;
|
||||||
WindowT *w3 = NULL;
|
WindowT *w3 = NULL;
|
||||||
ButtonT *b1 = NULL;
|
ButtonT *b1 = NULL;
|
||||||
|
|
||||||
vbeStartup(800, 600, 16);
|
(void)data;
|
||||||
mouseStartup();
|
|
||||||
desktop = guiStartup();
|
|
||||||
|
|
||||||
pointer = imageLoad("mouse.png");
|
pointer = imageLoad("mouse.png");
|
||||||
alpha = imagePixelGet(pointer, 5, 0);
|
alpha = imagePixelGet(pointer, 5, 0);
|
||||||
|
@ -71,30 +71,69 @@ void test(void) {
|
||||||
} while (!(!mouse->buttonRight && mouse->buttonRightWasDown)); // Exit on release of right-click.
|
} while (!(!mouse->buttonRight && mouse->buttonRightWasDown)); // Exit on release of right-click.
|
||||||
|
|
||||||
imageUnload(&pointer);
|
imageUnload(&pointer);
|
||||||
|
|
||||||
guiShutdown();
|
|
||||||
mouseShutdown();
|
|
||||||
vbeShutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
(void)argv;
|
|
||||||
|
|
||||||
if (argc > 1) {
|
uint16_t xResolution = 0;
|
||||||
|
uint16_t yResolution = 0;
|
||||||
|
uint16_t colorDepth = 0;
|
||||||
|
char logName[32] = { "log.log" };
|
||||||
|
char *c = NULL;
|
||||||
|
int16_t x = strlen(argv[0]);
|
||||||
|
|
||||||
|
// 0 1 2 3 4 5 6 7 8
|
||||||
|
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
printf("Kangaroo Punch Multi Player DOS Game Client Mark II\n");
|
||||||
|
printf("Copyright (C) 2020-2021 Scott Duensing scott@kangaroopunch.com\n\n");
|
||||||
|
|
||||||
|
// Find last portion of filename.
|
||||||
|
while (x > 0) {
|
||||||
|
if (argv[0][x] == '/' || argv[0][x] == '\\') break;
|
||||||
|
x--;
|
||||||
|
}
|
||||||
|
if (strlen(argv[0]) - x < 32) {
|
||||||
|
// Replace any extension with ".log"
|
||||||
|
strncpy(logName, &argv[0][x + 1], 31);
|
||||||
|
c = strstr(logName, ".");
|
||||||
|
if (c) *c = 0;
|
||||||
|
strncat(logName, ".log", 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
logOpen(logName, 0);
|
||||||
|
|
||||||
|
// Command line needs to have the desired resolution and color depth on it.
|
||||||
|
if (argc != 4) {
|
||||||
vbeShowInfo();
|
vbeShowInfo();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
xResolution = atoi(argv[1]);
|
||||||
|
yResolution = atoi(argv[2]);
|
||||||
|
colorDepth = atoi(argv[3]);
|
||||||
|
|
||||||
logOpen("test.log", 0);
|
// Do we have the video mode they asked for?
|
||||||
|
if (vbeStartup(xResolution, yResolution, colorDepth)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
test();
|
mouseStartup();
|
||||||
|
guiStartup();
|
||||||
|
taskStartup(64);
|
||||||
|
|
||||||
logClose();
|
taskCreate(test, NULL);
|
||||||
|
taskRun();
|
||||||
|
|
||||||
|
taskShutdown();
|
||||||
|
guiShutdown();
|
||||||
|
mouseShutdown();
|
||||||
|
vbeShutdown();
|
||||||
|
|
||||||
#ifdef memoryLeakShow
|
#ifdef memoryLeakShow
|
||||||
memoryLeaksShow();
|
memoryLeaksShow();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
logClose();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue