Skip to content

Instantly share code, notes, and snippets.

@rakslice
Last active November 27, 2022 00:11
Show Gist options
  • Save rakslice/f2329427874e38edc649f4b24bd7328c to your computer and use it in GitHub Desktop.
Save rakslice/f2329427874e38edc649f4b24bd7328c to your computer and use it in GitHub Desktop.
Classic Mac System 7 and later time manager InsTime/RmvTime stress test
/**
A program for testing InsTime/RmvTime cycles during timer events
Reading list:
- Inside Macintosh: Processes, Ch. 3 Time Manager, Using the Time Manager
To use, in THINK C 5.x
1. Create a THINK C 5.x project called "time manager stress test"
2. Add (Source -> Add...) this .c file
3. Add Mactraps (from Think C::Mac Libraries)
4. Add ANSI-small (from Think C::C Libraries)
5. Using ResEdit, create a new resource file in the same location as the project called "time manager stress test.rsrc"
6. Add a WIND resource with the default ID 128 and save it.
7. In THINK C, Project -> Run or Project -> Build Application...
*/
#include <Timer.h>
#include <stdio.h>
#define malloc NewPtr
#define free DisposePtr
#define APP_NEW(obj_type) ((obj_type *) NewPtr(sizeof(obj_type)))
#define SYS_NEW(obj_type) ((obj_type *) NewPtrSys(sizeof(obj_type)))
#define START_DELAY 1000 // ms
#define STEP_DELAY 0 // ms
long int i;
typedef void (*BetterTimerProcPtr)(TMTask * self);
struct TMTaskWithA5World {
TMTask tmTask;
long int a5World;
BetterTimerProcPtr innerTimerFunc;
};
pascal struct TMTaskWithA5World * GetTMInfo()
= {0x2E89}; // MOVE.L A1,(SP)
pascal void handleOuterTimer() {
int oldA5World;
struct TMTaskWithA5World * task;
task = GetTMInfo();
oldA5World = SetA5(task->a5World);
task->innerTimerFunc((TMTask *) task);
SetA5(oldA5World);
}
TMTask * createTMTask(BetterTimerProcPtr func) {
struct TMTaskWithA5World * task;
task = SYS_NEW(struct TMTaskWithA5World);
if (task) {
task->tmTask.tmAddr = &handleOuterTimer;
task->tmTask.tmCount = 0;
task->tmTask.tmWakeUp = 0;
task->tmTask.tmReserved = 0;
task->a5World = SetCurrentA5();
task->innerTimerFunc = func;
}
return (TMTask *) task;
}
void handleFirstTimer(TMTask * self) {
i++;
PrimeTime(self, STEP_DELAY);
}
void handleSecondTimer(TMTask * self) {
}
int main(void) {
TMTask *firstTask, *secondTask;
WindowPtr theWindow;
char buf[512];
int prevI;
BetterTimerProcPtr firstTimerHandler, secondTimerHandler;
InitGraf(&thePort);
InitFonts();
InitWindows();
firstTask = createTMTask(&handleFirstTimer);
secondTask = createTMTask(&handleSecondTimer);
theWindow = GetNewWindow(128, 0L, (WindowPtr)-1L);
SetPort(theWindow);
if (firstTask) {
InsTime(firstTask);
PrimeTime(firstTask, START_DELAY);
}
i = 0;
prevI = -1;
while(!Button()) {
if (i != prevI) {
prevI = i;
EraseRect(&theWindow->portRect);
MoveTo(30,50);
DrawString("\p- Continuous InsTime RmvTime cycles on a task in the foreground");
MoveTo(30,75);
sprintf(buf, " - Runs of a separate task from the Time Manager (count: %ld)", i);
buf[0] = strlen(buf) - 1;
DrawString(buf);
MoveTo(30,100);
DrawString("\pClick to close");
}
if (secondTask) {
InsTime(secondTask);
RmvTime(secondTask);
}
}
if (firstTask) {
RmvTime(firstTask);
free(firstTask);
}
if (secondTask)
free(secondTask);
return 0;
}
@rakslice
Copy link
Author

I created this to more easily reproduce a multithreading locking bug in Basilisk II / SheepShaver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment