예제 #1
0
파일: timer.cpp 프로젝트: habnabit/macemu
void sheepshaver_state::load_descs(int fd)
{
	TMDesc *prev = NULL, *first = NULL, *cur;
#if PRECISE_TIMING
	timer_thread_suspend();
	pthread_mutex_lock(&wakeup_time_lock);
#endif
	clear_descs();
	while (1) {
		cur = new TMDesc;
		read_exactly(cur, fd, sizeof *cur);
		if (!cur->task && !cur->next) {
			delete cur;
			break;
		}
		if (prev) {
			prev->next = cur;
		}
		if (!first) {
			first = cur;
		}
		prev = cur;
	}
	if (prev) {
		prev->next = NULL;
	}
	tmDescList = first;
#if PRECISE_TIMING
	pthread_mutex_unlock(&wakeup_time_lock);
	timer_thread_resume();
	assert(suspend_count == 0);
#endif
}
예제 #2
0
void TimerInterrupt(void)
{
//	D(bug("TimerIRQ\n"));

	// Look for active TMTasks that have expired
	tm_time_t now;
	timer_current_time(now);
	TMDesc *desc = tmDescList;
	while (desc) {
		TMDesc *next = desc->next;
		uint32 tm = desc->task;
		if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc->wakeup, now) <= 0) {

			// Found one, mark as inactive and remove it from the Time Manager queue
			WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
			dequeue_tm(tm);

			// Call timer function
			uint32 addr = ReadMacInt32(tm + tmAddr);
			if (addr) {
				D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr));
				M68kRegisters r;
				r.a[0] = addr;
				r.a[1] = tm;
				Execute68k(r.a[0], &r);
				D(bug(" returned from TimeTask\n"));
			}
		}
		desc = next;
	}

#if PRECISE_TIMING
	// Look for next task to be called and set wakeup_time
#if PRECISE_TIMING_BEOS
	while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
	suspend_thread(timer_thread);
#endif
#if PRECISE_TIMING_MACH
	semaphore_wait(wakeup_time_sem);
	thread_suspend(timer_thread);
#endif
#if PRECISE_TIMING_POSIX
	timer_thread_suspend();
	pthread_mutex_lock(&wakeup_time_lock);
#endif
	wakeup_time = wakeup_time_max;
	for (TMDesc *d = tmDescList; d; d = d->next)
		if ((ReadMacInt16(d->task + qType) & 0x8000))
			if (timer_cmp_time(d->wakeup, wakeup_time) < 0)
				wakeup_time = d->wakeup;
#if PRECISE_TIMING_BEOS
	release_sem(wakeup_time_sem);
	thread_info info;
	do {
		resume_thread(timer_thread);			// This will unblock the thread
		get_thread_info(timer_thread, &info);
	} while (info.state == B_THREAD_SUSPENDED);	// Sometimes, resume_thread() doesn't work (BeOS bug?)
#endif
#if PRECISE_TIMING_MACH
	semaphore_signal(wakeup_time_sem);
	thread_abort(timer_thread);
	thread_resume(timer_thread);
#endif
#if PRECISE_TIMING_POSIX
	pthread_mutex_unlock(&wakeup_time_lock);
	timer_thread_resume();
	assert(suspend_count == 0);
#endif
#endif
}
예제 #3
0
int16 PrimeTime(uint32 tm, int32 time)
{
	D(bug("PrimeTime %08lx, time %ld\n", tm, time));

	// Find descriptor
	TMDesc *desc = find_desc(tm);
	if (!desc) {
		printf("FATAL: PrimeTime(%08lx): Descriptor not found\n", (long unsigned int)tm);
		return 0;
	}

	// Convert delay time
	tm_time_t delay;
	timer_mac2host_time(delay, time);

	// Extended task?
	if (ReadMacInt16(tm + qType) & 0x4000) {

		// Yes, tmWakeUp set?
		if (ReadMacInt32(tm + tmWakeUp)) {

			// PrimeTime(0) can either mean (a) "the task runs as soon as interrupts are enabled"
			// or (b) "continue previous delay" if an expired task was stopped via RmvTime() and
			// then re-installed using InsXTime(). Since tmWakeUp was set, this is case (b).
			// The remaining time was saved in tmCount by RmvTime().
			if (time == 0) {
				timer_mac2host_time(delay, ReadMacInt16(tm + tmCount));
			}

			// Yes, calculate wakeup time relative to last scheduled time
			tm_time_t wakeup;
			timer_add_time(wakeup, desc->wakeup, delay);
			desc->wakeup = wakeup;

		} else {

			// No, calculate wakeup time relative to current time
			tm_time_t now;
			timer_current_time(now);
			timer_add_time(desc->wakeup, now, delay);
		}

		// Set tmWakeUp to indicate that task was scheduled
		WriteMacInt32(tm + tmWakeUp, 0x12345678);

	} else {

		// Not extended task, calculate wakeup time relative to current time
		tm_time_t now;
		timer_current_time(now);
		timer_add_time(desc->wakeup, now, delay);
	}

	// Make task active and enqueue it in the Time Manager queue
#if PRECISE_TIMING_BEOS
	while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
	suspend_thread(timer_thread);
#endif
#ifdef PRECISE_TIMING_MACH
	semaphore_wait(wakeup_time_sem);
	thread_suspend(timer_thread);
#endif
#if PRECISE_TIMING_POSIX
	timer_thread_suspend();
	pthread_mutex_lock(&wakeup_time_lock);
#endif
	WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
	enqueue_tm(tm);
#if PRECISE_TIMING
	// Look for next task to be called and set wakeup_time
	wakeup_time = wakeup_time_max;
	for (TMDesc *d = tmDescList; d; d = d->next)
		if ((ReadMacInt16(d->task + qType) & 0x8000))
			if (timer_cmp_time(d->wakeup, wakeup_time) < 0)
				wakeup_time = d->wakeup;
#ifdef PRECISE_TIMING_BEOS
	release_sem(wakeup_time_sem);
	thread_info info;
	do {
		resume_thread(timer_thread);			// This will unblock the thread
		get_thread_info(timer_thread, &info);
	} while (info.state == B_THREAD_SUSPENDED);	// Sometimes, resume_thread() doesn't work (BeOS bug?)
#endif
#ifdef PRECISE_TIMING_MACH
	semaphore_signal(wakeup_time_sem);
	thread_abort(timer_thread);
	thread_resume(timer_thread);
#endif
#ifdef PRECISE_TIMING_POSIX
	pthread_mutex_unlock(&wakeup_time_lock);
	timer_thread_resume();
	assert(suspend_count == 0);
#endif
#endif
	return 0;
}
예제 #4
0
int16 RmvTime(uint32 tm)
{
	D(bug("RmvTime %08lx\n", tm));

	// Find descriptor
	TMDesc *desc = find_desc(tm);
	if (!desc) {
		printf("WARNING: RmvTime(%08lx): Descriptor not found\n", (long unsigned int)tm);
		return 0;
	}

	// Task active?
#if PRECISE_TIMING_BEOS
	while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
	suspend_thread(timer_thread);
#endif
#ifdef PRECISE_TIMING_MACH
	semaphore_wait(wakeup_time_sem);
	thread_suspend(timer_thread);
#endif
#if PRECISE_TIMING_POSIX
	timer_thread_suspend();
	pthread_mutex_lock(&wakeup_time_lock);
#endif
	if (ReadMacInt16(tm + qType) & 0x8000) {

		// Yes, make task inactive and remove it from the Time Manager queue
		WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
		dequeue_tm(tm);
#if PRECISE_TIMING
		// Look for next task to be called and set wakeup_time
		wakeup_time = wakeup_time_max;
		for (TMDesc *d = tmDescList; d; d = d->next)
			if ((ReadMacInt16(d->task + qType) & 0x8000))
				if (timer_cmp_time(d->wakeup, wakeup_time) < 0)
					wakeup_time = d->wakeup;
#endif

		// Compute remaining time
		tm_time_t remaining, current;
		timer_current_time(current);
		timer_sub_time(remaining, desc->wakeup, current);
		WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining));
	} else
		WriteMacInt32(tm + tmCount, 0);
	D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount)));
#if PRECISE_TIMING_BEOS
	release_sem(wakeup_time_sem);
	thread_info info;
	do {
		resume_thread(timer_thread);			// This will unblock the thread
		get_thread_info(timer_thread, &info);
	} while (info.state == B_THREAD_SUSPENDED);	// Sometimes, resume_thread() doesn't work (BeOS bug?)
#endif
#ifdef PRECISE_TIMING_MACH
	semaphore_signal(wakeup_time_sem);
	thread_abort(timer_thread);
	thread_resume(timer_thread);
#endif
#if PRECISE_TIMING_POSIX
	pthread_mutex_unlock(&wakeup_time_lock);
	timer_thread_resume();
	assert(suspend_count == 0);
#endif

	// Free descriptor
	free_desc(desc);
	return 0;
}