Пример #1
0
static void coopth_callf_chk(struct coopth_t *thr,
	struct coopth_per_thread_t *pth)
{
    if (!thr->ctxh.pre)
	dosemu_error("coopth: unsafe attach\n");
    coopth_callf(thr, pth);
}
Пример #2
0
static void check_tid(int tid)
{
    if (tid < 0 || tid >= coopth_num) {
	dosemu_error("Wrong tid\n");
	leavedos(2);
    }
}
Пример #3
0
static void do_awake(struct coopth_per_thread_t *pth)
{
    if (pth->st.state != COOPTHS_SLEEPING) {
	dosemu_error("wakeup on non-sleeping thread %i\n", *pth->data.tid);
	return;
    }
    pth->st = SW_ST(AWAKEN);
}
Пример #4
0
void coopth_sleep(void)
{
    assert(_coopth_is_in_thread());
    if (!is_detached() && !isset_IF())
	dosemu_error("sleep with interrupts disabled\n");
    switch_state(COOPTH_SLEEP);
    check_cancel();
}
Пример #5
0
static void ensure_attached(void)
{
    struct coopth_thrdata_t *thdata = co_get_data(co_current());
    if (!thdata->attached) {
	dosemu_error("Not allowed for detached thread\n");
	leavedos(2);
    }
}
Пример #6
0
void coopth_wait(void)
{
    assert(_coopth_is_in_thread());
    ensure_attached();
    if (!isset_IF())
	dosemu_error("sleep with interrupts disabled\n");
    switch_state(COOPTH_WAIT);
    check_cancel();
}
Пример #7
0
static void ensure_attached(void)
{
    struct coopth_thrdata_t *thdata = co_get_data(co_current(co_handle));
    if (!thdata->attached) {
	dosemu_error("Not allowed for detached thread %i, %s\n",
		*thdata->tid, coopthreads[*thdata->tid].name);
	leavedos(2);
    }
}
Пример #8
0
int register_render_system(struct render_system *render_system)
{
  if (Render) {
    dosemu_error("multiple gfx renderers not supported, please report a bug!\n");
    return 0;
  }
  Render = render_system;
  return 1;
}
Пример #9
0
static void do_awake(struct coopth_per_thread_t *pth)
{
    if (pth->st.state != COOPTHS_SLEEPING) {
	dosemu_error("wakeup on non-sleeping thread %i\n", *pth->data.tid);
	return;
    }
    pth->st = SW_ST(AWAKEN);
    if (!pth->data.attached)
	pth->quick_sched = 1;	// optimize DPMI switches
}
Пример #10
0
static int __coopth_is_in_thread(int warn, const char *f)
{
    if (!thread_running && warn) {
	static int warned;
	if (!warned) {
	    warned = 1;
	    dosemu_error("Coopth: %s: not in thread!\n", f);
	}
    }
    return thread_running;
}
Пример #11
0
static void render_text_lock(void)
{
  if (!render_text || text_locked) {
    dosemu_error("render not in text mode!\n");
    leavedos(95);
    return;
  }
  text_locked++;
  if (!text_really_locked) {
    dst_image = render_lock();
    text_really_locked = 1;
  }
}
Пример #12
0
int coopth_unsafe_detach(int tid)
{
    struct coopth_t *thr;
    struct coopth_per_thread_t *pth;
    check_tid(tid);
    dosemu_error("coopth_unsafe_detach() called\n");
    thr = &coopthreads[tid];
    pth = current_thr(thr);
    assert(pth->data.attached);
    /* this is really unsafe and should be used only if
     * the DOS side of the thread have disappeared. */
    pth->data.attached = 0;
    return 0;
}
Пример #13
0
static void coopth_callf(struct coopth_t *thr, struct coopth_per_thread_t *pth)
{
    assert(!pth->data.attached);
    if (thr->ctxh.pre)
	thr->ctxh.pre(thr->tid);
    if (ctx_is_valid) {
	int ok = ctx_is_valid();
	if (!ok)
	    dosemu_error("coopth: unsafe context switch\n");
    }
    pth->ret_cs = SREG(cs);
    pth->ret_ip = LWORD(eip);
    SREG(cs) = BIOS_HLT_BLK_SEG;
    LWORD(eip) = thr->hlt_off;
    threads_joinable++;
    pth->data.attached = 1;
}
Пример #14
0
static void ensure_single(struct coopth_thrdata_t *thdata)
{
    struct coopth_t *thr = &coopthreads[*thdata->tid];
    if (thr->cur_thr != 1)
	dosemu_error("coopth: nested=%i (expected 1)\n", thr->cur_thr);
}
Пример #15
0
int coopth_start(int tid, coopth_func_t func, void *arg)
{
    struct coopth_t *thr;
    struct coopth_per_thread_t *pth;
    int tn;

    check_tid(tid);
    thr = &coopthreads[tid];
    assert(thr->tid == tid);
    if (thr->cur_thr >= MAX_COOP_RECUR_DEPTH) {
	int i;
	error("Coopthreads recursion depth exceeded, %s off=%x\n",
		thr->name, thr->off);
	for (i = 0; i < thr->cur_thr; i++) {
	    error("\tthread %i state %i dbg %#x\n",
		    i, thr->pth[i].st.state, thr->pth[i].dbg);
	}
	leavedos(2);
	return -1;
    }
    tn = thr->cur_thr++;
    pth = &thr->pth[tn];
    if (thr->cur_thr > thr->max_thr) {
	size_t stk_size = COOP_STK_SIZE();
	thr->max_thr = thr->cur_thr;
#ifndef MAP_STACK
#define MAP_STACK 0
#endif
	pth->stack = mmap(NULL, stk_size, PROT_READ | PROT_WRITE,
		MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
	if (pth->stack == MAP_FAILED) {
	    error("Unable to allocate stack\n");
	    leavedos(21);
	    return 1;
	}
	pth->stk_size = stk_size;
    }
    pth->data.tid = &thr->tid;
    pth->data.attached = 0;
    pth->data.posth_num = 0;
    pth->data.sleep.func = NULL;
    pth->data.clnup.func = NULL;
    pth->data.udata_num = 0;
    pth->data.cancelled = 0;
    pth->data.left = 0;
    pth->args.thr.func = func;
    pth->args.thr.arg = arg;
    pth->args.thrdata = &pth->data;
    pth->dbg = LWORD(eax);	// for debug
    pth->thread = co_create(coopth_thread, &pth->args, pth->stack,
	    pth->stk_size);
    if (!pth->thread) {
	error("Thread create failure\n");
	leavedos(2);
	return -1;
    }
    pth->st = ST(RUNNING);
    if (tn == 0) {
	assert(threads_active < MAX_ACT_THRS);
	active_tids[threads_active++] = tid;
    } else if (thr->pth[tn - 1].st.state == COOPTHS_SLEEPING) {
	static int logged;
	/* will have problems with wake-up by tid. It is possible
	 * to do a wakeup-specific lookup, but this is nasty, and
	 * the recursion itself is nasty too. Lets just print an
	 * error to force the caller to create a separate thread.
	 * vc.c does this to not sleep in the sighandling thread.
	 */
	if (!logged) {
	    dosemu_error("thread %s recursed (%i) over sleep\n",
		    thr->name, thr->cur_thr);
	    logged = 1;
	}
    }
    threads_total++;
    if (!thr->detached)
	coopth_callf(thr, pth);
    return 0;
}
Пример #16
0
static void __thread_run(struct coopth_t *thr, struct coopth_per_thread_t *pth)
{
    switch (pth->st.state) {
    case COOPTHS_NONE:
	error("Coopthreads error switch to inactive thread, exiting\n");
	leavedos(2);
	break;
    case COOPTHS_RUNNING: {
	int jr, lr;
	enum CoopthRet tret;
	/* We have 2 kinds of recursion:
	 *
	 * 1. (call it recursive thread invocation)
	 *	main_thread -> coopth_start(thread1_func) -> return
	 *		thread1_func() -> coopth_start(thread2_func) -> return
	 *		(thread 1 returned, became zombie)
	 *			thread2_func() -> return
	 *			thread2 joined
	 *		thread1 joined
	 *	main_thread...
	 *
	 * 2. (call it nested thread invocation)
	 *	main_thread -> coopth_start(thread1_func) -> return
	 *		thread1_func() -> do_int_call_back() ->
	 *		run_int_from_hlt() ->
	 *		coopth_start(thread2_func) -> return
	 *			thread2_func() -> return
	 *			thread2 joined
	 *		-> return from do_int_call_back() ->
	 *		return from thread1_func()
	 *		thread1 joined
	 *	main_thread...
	 *
	 * Both cases are supported here, but the nested invocation
	 * is not supposed to be used as being too complex.
	 * Since do_int_call_back() was converted
	 * to coopth API, the nesting is avoided.
	 * If not true, we print an error.
	 */
	if (joinable_running) {
	    static int warned;
	    if (!warned) {
		warned = 1;
		dosemu_error("Nested thread invocation detected, please fix! "
			"(at=%i)\n", pth->data.attached);
	    }
	}
	jr = joinable_running;
	if (pth->data.attached)
	    joinable_running++;
	lr = left_running;
	if (pth->data.left) {
	    assert(!pth->data.attached);
	    left_running++;
	}
	thread_running++;
	tret = do_run_thread(thr, pth);
	thread_running--;
	left_running = lr;
	joinable_running = jr;
	if (tret == COOPTH_WAIT && pth->data.attached)
	    dosemu_sleep();
	if (tret == COOPTH_SLEEP || tret == COOPTH_WAIT ||
		tret == COOPTH_YIELD) {
	    if (pth->data.sleep.func) {
		/* oneshot sleep handler */
		pth->data.sleep.func(pth->data.sleep.arg);
		pth->data.sleep.func = NULL;
	    }
	    if (thr->sleeph.pre)
		thr->sleeph.pre(thr->tid);
	}
	/* normally we don't exit with RUNNING state any longer.
	 * this was happening in prev implementations though, so
	 * remove that assert if it ever hurts. */
	assert(pth->st.state != COOPTHS_RUNNING);
	break;
    }
    case COOPTHS_SLEEPING:
	if (pth->data.attached)
	    dosemu_sleep();
	break;
    case COOPTHS_SWITCH:
	pth->st.switch_fn(thr, pth);
	break;
    }
}
Пример #17
0
static void check_locked(void)
{
  if (!render_locked)
    dosemu_error("render not locked!\n");
}