示例#1
0
static void
insert_timer( mtimer_t *t )
{
	mtimer_t **tc;
	ullong mark = ((ullong)t->tbu << 32) | t->tbl;
	ullong omark = ((ullong)ts.overflow->tbu <<32) | ts.overflow->tbl;

	if( (llong)(mark - omark) > 0 ) {
		t->next = ts.overflow->next;
		ts.overflow->next = t;
		t->flags |= TF_OVERFLOW;
		return;
	}

	for( tc=&ts.head; *tc && (int)((**tc).tbl - t->tbl) < 0 ; tc=&(*tc)->next )
		;
	t->next = *tc;
	*tc = t;

	if( t == ts.head ) {
		mregs->timer_stamp = t->tbl;
		if( likely(is_main_thread()) )
			mregs->flag_bits |= fb_RecalcDecInt;
		else {
			__recalc_timer = 1;
			interrupt_emulation();
		}
	}
}
示例#2
0
void assert_is_background_thread(const char *who)
{
    if (is_main_thread() && ! thread_assertions_configured_for_testing) {
        fprintf(stderr, "Warning: %s called on the main thread (may block!). Break on debug_thread_error to debug.\n", who);
        debug_thread_error();
    }
}
示例#3
0
void iothread_perform_on_main(void_function_t &&func) {
    if (is_main_thread()) {
        func();
        return;
    }

    // Make a new request. Note we are synchronous, so this can be stack allocated!
    main_thread_request_t req(std::move(func));

    // Append it. Do not delete the nested scope as it is crucial to the proper functioning of this
    // code by virtue of the lock management.
    {
        scoped_lock queue_lock(s_main_thread_request_q_lock);
        s_main_thread_request_queue.push(&req);
    }

    // Tell the pipe.
    const char wakeup_byte = IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE;
    assert_with_errno(write_loop(s_write_pipe, &wakeup_byte, sizeof wakeup_byte) != -1);

    // Wait on the condition, until we're done.
    std::unique_lock<std::mutex> perform_lock(s_main_thread_performer_lock);
    while (!req.done) {
        // It would be nice to support checking for cancellation here, but the clients need a
        // deterministic way to clean up to avoid leaks
        s_main_thread_performer_cond.wait(perform_lock);
    }

    // Ok, the request must now be done.
    assert(req.done);
}
示例#4
0
void
thread_exit(void* ret_val)
{
    proc->ret_val=ret_val;

    if(is_main_thread(proc)) {
        // check if last running thread
        if(proc->tcount <= 1) {
            exit();
        } else {
            // Wait for children to exit
            acquire(&ptable.lock);
            sleep(proc, &ptable.lock);
            release(&ptable.lock);
            exit();
        }
    }

    // Normal thread exit
    acquire(&ptable.lock);

    //iput(proc->cwd);
    proc->parent->tcount--;
    proc->cwd = 0;
    // Parent might be sleeping in wait().
    wakeup1(proc->parent);

    // Jump into the scheduler, never to return.
    proc->state = ZOMBIE;
    sched();
    panic("thread zombie exit");
}
示例#5
0
int xio_exec_req(const struct node_id *nid, struct sd_req *hdr, void *data,
		 bool (*need_retry)(uint32_t epoch), uint32_t epoch,
		 uint32_t max_count)
{
	struct xio_context *ctx = xio_context_create(NULL, 0, -1);
	struct client_data cli = { .ctx = ctx };
	struct xio_connection *conn = sd_xio_create_connection(ctx, nid, &cli);
	struct xio_msg xreq;
	struct sd_rsp rsp;

	sd_assert(!is_main_thread());

	memset(&rsp, 0, sizeof(rsp));
	memset(&xreq, 0, sizeof(xreq));
	client_msg_vec_init(&xreq);
	memset(&rsp, 0, sizeof(rsp));
	msg_prep_for_send(hdr, &rsp, data, &xreq);

	xio_send_request(conn, &xreq);
	xio_context_run_loop(ctx, XIO_INFINITE);

	msg_finalize(hdr, data, cli.rsp);

	xio_connection_destroy(conn);
	xio_context_destroy(ctx);

	return 0;
}
示例#6
0
 /// Indicate whether we should cancel wildcard expansion. This latches 'interrupt'.
 bool interrupted() {
     if (!did_interrupt) {
         did_interrupt = (is_main_thread() ? reader_test_and_clear_interrupted()
                                           : reader_thread_job_is_stale());
     }
     return did_interrupt;
 }
示例#7
0
int
thread_getId(void)
{
    if(is_main_thread(proc))
        return -1;
    return proc->tid;
}
示例#8
0
void assert_is_main_thread(const char *who)
{
    if (! is_main_thread() && ! thread_assertions_configured_for_testing) {
        fprintf(stderr, "Warning: %s called off of main thread. Break on debug_thread_error to debug.\n", who);
        debug_thread_error();
    }
}
示例#9
0
struct proc* get_main_thread(struct proc* p)
{
    if(is_main_thread(p)) {
        return p;
    }

    return p->parent;
}
示例#10
0
hrtime_t time_get(void) {
	if(use_hires) {
		assert(is_main_thread());
		time_update();
		return time_current;
	}

	return SDL_GetTicks() * (HRTIME_RESOLUTION / 1000);
}
示例#11
0
static void
print_guard( void )
{
	/* printm is in principal the only FPU-unsafe function we call. 
	 * We use this hook to automatically shield the FPU when necessary.
	 */
	if( is_main_thread() )
		shield_fpu( mregs );
}
void AIStateMachine::idle(void)
{
  DoutEntering(dc::statemachine, "AIStateMachine::idle() [" << (void*)this << "]");
  llassert(is_main_thread());
  llassert(!mIdle);
  mIdle = true;
  mSleep = 0;
#ifdef SHOW_ASSERT
  mCalledThreadUnsafeIdle = true;
#endif
}
void AIStateMachine::idle(state_type current_run_state)
{
  DoutEntering(dc::statemachine, "AIStateMachine::idle(" << state_str(current_run_state) << ") [" << (void*)this << "]");
  llassert(is_main_thread());
  llassert(!mIdle);
  mSetStateLock.lock();
  // Only go idle if the run state is (still) what we expect it to be.
  // Otherwise assume that another thread called set_state() and continue running.
  if (current_run_state == mRunState)
  {
	mIdle = true;
	mSleep = 0;
  }
  mSetStateLock.unlock();
}
示例#14
0
文件: llapr.cpp 项目: Kiera/Crow
apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep)
{
	llassert_always(!mFile);
	llassert_always(!mCurrentFilePoolp);

	// Access the pool and increment it's reference count.
	// The reference count of LLVolatileAPRPool objects will be decremented
	// again in LLAPRFile::close by calling mCurrentFilePoolp->clearVolatileAPRPool().
	apr_pool_t* pool;
	if (access_type == local)
	{
	  	// Use a "volatile" thread-local pool.
		mCurrentFilePoolp = LLVolatileAPRPool::getLocalAPRFilePool();
		pool = mCurrentFilePoolp->getVolatileAPRPool();
	}
	else
	{
	  	llassert(is_main_thread());
		pool = gAPRPoolp;
	}
	apr_status_t s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, pool);
	if (s != APR_SUCCESS || !mFile)
	{
		mFile = NULL ;
		close() ;
		if (sizep)
		{
			*sizep = 0;
		}
		return s;
	}

	if (sizep)
	{
		S32 file_size = 0;
		apr_off_t offset = 0;
		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
		{
			llassert_always(offset <= 0x7fffffff);
			file_size = (S32)offset;
			offset = 0;
			apr_file_seek(mFile, APR_SET, &offset);
		}
		*sizep = file_size;
	}

	return s;
}
示例#15
0
void 
interrupt_emulation( void )
{
	assert( mregs );
	mregs->interrupt = 1; 

	/* if we are the main thread, then it is pointless to call abort_doze... */
	if( unlikely(!is_main_thread()) ) {
		abort_doze();

		/* On SMP we might have to send an IPI to the main thread. The
		 * latency in the IPI-case is on average about 8.8us (on a 1.25 GHz
		 * SMP machine) and about 1us otherwise.
		 */
		if( mregs->in_virtual_mode )
			_smp_send_ipi();
	}
}
示例#16
0
void
clear_thread(struct proc* p)
{
    if(is_main_thread(p))
        panic("main thread clear");

    kfree(p->kstack);
    p->kstack = 0;
    p->state = UNUSED;
    p->pid = 0;
    p->pgdir = 0;
    p->parent = 0;
    p->name[0] = 0;
    p->killed = 0;
    p->last_tid = 0;
    p->cwd = 0;
    p->tid = 0;
    p->ret_val = 0;
    p->tcount = 0;
    p->other_thread_waiting = 0;
}
示例#17
0
	/*
	 *	@brief	Load balances the pool.
	 *			Creates/destroys workers, as needed.
	 */
	void load_balance() {
		assert(is_main_thread());

		const auto now = std::chrono::high_resolution_clock::now();
		std::chrono::duration<float> time_since_last_pool_balance = now - last_pool_balance;
		if (time_since_last_pool_balance.count() < .05f)
			return;
		last_pool_balance = now;

		float idle_frac = .0f;
		float kernel_frac = .0f;
		float user_frac = .0f;
		if (!sys_times.get_times_since_last_call(idle_frac, kernel_frac, user_frac))
			return;

		// Check for dead workers (e.g. exception thrown)
		for (auto it = workers.begin(); it != workers.end();) {
			if (it->is_terminated())
				it = workers.erase(it);
			else
				++it;
		}

		// Load balance
		const unsigned min_threads = min_worker_threads();
		const auto req = get_pending_requests_count();
		const auto threads_sleeping = get_sleeping_workers_count();
		const auto total_workers_count = get_workers_count();
		if (threads_sleeping == 0 &&
			idle_frac > idle_time_threshold_for_new_worker &&
			total_workers_count < max_worker_threads()) {
			spawn_worker();
		}
		else if (workers.size() > min_threads &&
			(kernel_frac > kernel_time_thershold_for_despawn_extra_worker ||
				(req == 0 && idle_frac > idle_time_threshold_for_despawn_surplus_worker) ||
				threads_sleeping > 1)) {
			despawn_worker();
		}
	}
示例#18
0
static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
        HashmapBase *h;
        const struct hashmap_type_info *hi = &hashmap_type_info[type];
        bool use_pool;

        use_pool = is_main_thread();

        h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);

        if (!h)
                return NULL;

        h->type = type;
        h->from_pool = use_pool;
        h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops;

        if (type == HASHMAP_TYPE_ORDERED) {
                OrderedHashmap *lh = (OrderedHashmap*)h;
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
        }

        reset_direct_storage(h);

        if (!shared_hash_key_initialized) {
                random_bytes(shared_hash_key, sizeof(shared_hash_key));
                shared_hash_key_initialized= true;
        }

#ifdef ENABLE_DEBUG_HASHMAP
        h->debug.func = func;
        h->debug.file = file;
        h->debug.line = line;
        assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
        LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
        assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
#endif

        return h;
}
示例#19
0
int iothread_perform_on_main_base(int (*handler)(void *), void *context) {
    // If this is the main thread, just do it.
    if (is_main_thread()) {
        return handler(context);
    }

    // Make a new request. Note we are synchronous, so this can be stack allocated!
    MainThreadRequest_t req;
    req.handler = handler;
    req.context = context;
    req.handlerResult = 0;
    req.done = false;

    // Append it. Do not delete the nested scope as it is crucial to the proper functioning of this
    // code by virtue of the lock management.
    {
        scoped_lock queue_lock(s_main_thread_request_queue_lock);
        s_main_thread_request_queue.push(&req);
    }

    // Tell the pipe.
    const char wakeup_byte = IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE;
    VOMIT_ON_FAILURE(!write_loop(s_write_pipe, &wakeup_byte, sizeof wakeup_byte));

    // Wait on the condition, until we're done.
    scoped_lock perform_lock(s_main_thread_performer_lock);
    while (!req.done) {
        // It would be nice to support checking for cancellation here, but the clients need a
        // deterministic way to clean up to avoid leaks
        VOMIT_ON_FAILURE(
            pthread_cond_wait(&s_main_thread_performer_condition, &s_main_thread_performer_lock));
    }

    // Ok, the request must now be done.
    assert(req.done);
    return req.handlerResult;
}
示例#20
0
int
thread_create(void* (*start_func)(), void* stack, uint stack_size)
{
    int i;
    struct proc *np;

    // Allocate process.
    if((np = allocproc()) == 0)
        return -1;

    // Copy process state from p.
    np->pgdir=proc->pgdir;
    np->sz = proc->sz;
    if(is_main_thread(proc))
        np->parent = proc;
    else
        np->parent = proc->parent;
    *np->tf = *proc->tf;

    // Clear %eax so that fork returns 0 in the child.
    //np->tf->eax = 0;
    np->tf->esp = (uint) stack+stack_size;
    np->tf->eip = (uint) start_func;

    for(i = 0; i < NOFILE; i++)
        if(proc->ofile[i])
            np->ofile[i] = proc->ofile[i];
    np->cwd = proc->cwd;

    np->parent->last_tid++;
    np->tid = np->parent->last_tid;
    np->parent->tcount++;
    np->tcount = 0;
    np->state = RUNNABLE;
    safestrcpy(np->name, proc->name, sizeof(proc->name));
    return np->tid;
}
示例#21
0
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards.

   Because this function calls itself recursively with substrings,
   it's important that the parameters be raw pointers instead of wcstring,
   which would be too expensive to construct for all substrings.
 */
static int wildcard_expand_internal(const wchar_t *wc,
                                    const wchar_t * const base_dir,
                                    expand_flags_t flags,
                                    std::vector<completion_t> *out,
                                    std::set<wcstring> &completion_set,
                                    std::set<file_id_t> &visited_files)
{
    /* Variables for traversing a directory */
    DIR *dir;

    /* The result returned */
    int res = 0;


    //  debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

    if (is_main_thread() ? reader_interrupted() : reader_thread_job_is_stale())
    {
        return -1;
    }

    if (!wc || !base_dir)
    {
        debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
        return 0;
    }

    const size_t base_dir_len = wcslen(base_dir);
    const size_t wc_len = wcslen(wc);

    if (flags & ACCEPT_INCOMPLETE)
    {
        /*
           Avoid excessive number of returned matches for wc ending with a *
        */
        if (wc_len > 0 && (wc[wc_len-1]==ANY_STRING))
        {
            wchar_t * foo = wcsdup(wc);
            foo[wc_len-1]=0;
            int res = wildcard_expand_internal(foo, base_dir, flags, out, completion_set, visited_files);
            free(foo);
            return res;
        }
    }

    /* Determine if we are the last segment */
    const wchar_t * const next_slash = wcschr(wc,L'/');
    const bool is_last_segment = (next_slash == NULL);
    const size_t wc_segment_len = next_slash ? next_slash - wc : wc_len;
    const wcstring wc_segment = wcstring(wc, wc_segment_len);
    
    /* Maybe this segment has no wildcards at all. If this is not the last segment, and it has no wildcards, then we don't need to match against the directory contents, and in fact we don't want to match since we may not be able to read it anyways (#2099). Don't even open the directory! */
    const bool segment_has_wildcards = wildcard_has(wc_segment, true /* internal, i.e. look for ANY_CHAR instead of ? */);
    if (! segment_has_wildcards && ! is_last_segment)
    {
        wcstring new_base_dir = make_path(base_dir, wc_segment);
        new_base_dir.push_back(L'/');
        
        /* Skip multiple separators */
        assert(next_slash != NULL);
        const wchar_t *new_wc = next_slash;
        while (*new_wc==L'/')
        {
            new_wc++;
        }
        /* Early out! */
        return wildcard_expand_internal(new_wc, new_base_dir.c_str(), flags, out, completion_set, visited_files);
    }
    
    /* Test for recursive match string in current segment */
    const bool is_recursive = (wc_segment.find(ANY_STRING_RECURSIVE) != wcstring::npos);
    

    const wchar_t *base_dir_or_cwd = (base_dir[0] == L'\0') ? L"." : base_dir;
    if (!(dir = wopendir(base_dir_or_cwd)))
    {
        return 0;
    }
    
    /*
      Is this segment of the wildcard the last?
    */
    if (is_last_segment)
    {
        /*
          Wildcard segment is the last segment,

          Insert all matching files/directories
        */
        if (wc[0]=='\0')
        {
            /*
              The last wildcard segment is empty. Insert everything if
              completing, the directory itself otherwise.
            */
            if (flags & ACCEPT_INCOMPLETE)
            {
                wcstring next;
                while (wreaddir(dir, next))
                {
                    if (next[0] != L'.')
                    {
                        wcstring long_name = make_path(base_dir, next);

                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out, long_name, next, L"", flags);
                        }
                    }
                }
            }
            else
            {
                res = 1;
                insert_completion_if_missing(base_dir, out, &completion_set);
            }
        }
        else
        {
            /* This is the last wildcard segment, and it is not empty. Match files/directories. */
            wcstring name_str;
            while (wreaddir(dir, name_str))
            {
                if (flags & ACCEPT_INCOMPLETE)
                {

                    const wcstring long_name = make_path(base_dir, name_str);

                    /* Test for matches before stating file, so as to minimize the number of calls to the much slower stat function. The only expand flag we care about is EXPAND_FUZZY_MATCH; we have no complete flags. */
                    std::vector<completion_t> test;
                    if (wildcard_complete(name_str, wc, L"", NULL, &test, flags & EXPAND_FUZZY_MATCH, 0))
                    {
                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out, long_name, name_str, wc, flags);

                        }
                    }
                }
                else
                {
                    if (wildcard_match(name_str, wc, true /* skip files with leading dots */))
                    {
                        const wcstring long_name = make_path(base_dir, name_str);
                        int skip = 0;

                        if (is_recursive)
                        {
                            /*
                              In recursive mode, we are only
                              interested in adding files -directories
                              will be added in the next pass.
                            */
                            struct stat buf;
                            if (!wstat(long_name, &buf))
                            {
                                skip = S_ISDIR(buf.st_mode);
                            }
                        }
                        if (! skip)
                        {
                            insert_completion_if_missing(long_name, out, &completion_set);
                        }
                        res = 1;
                    }
                }
            }
        }
    }

    if ((! is_last_segment) || is_recursive)
    {
        /*
          Wilcard segment is not the last segment.  Recursively call
          wildcard_expand for all matching subdirectories.
        */

        /*
          In recursive mode, we look through the directory twice. If
          so, this rewind is needed.
        */
        rewinddir(dir);

        /* new_dir is a scratch area containing the full path to a file/directory we are iterating over */
        wcstring new_dir = base_dir;

        wcstring name_str;
        while (wreaddir(dir, name_str))
        {
            /*
              Test if the file/directory name matches the whole
              wildcard element, i.e. regular matching.
            */
            bool whole_match = wildcard_match(name_str, wc_segment, true /* ignore leading dots */);
            bool partial_match = false;

            /*
               If we are doing recursive matching, also check if this
               directory matches the part up to the recusrive
               wildcard, if so, then we can search all subdirectories
               for matches.
            */
            if (is_recursive)
            {
                const wchar_t *end = wcschr(wc, ANY_STRING_RECURSIVE);
                wchar_t *wc_sub = wcsndup(wc, end-wc+1);
                partial_match = wildcard_match(name_str, wc_sub, true /* ignore leading dots */);
                free(wc_sub);
            }

            if (whole_match || partial_match)
            {
                struct stat buf;
                int new_res;

                // new_dir is base_dir + some other path components
                // Replace everything after base_dir with the new path component
                new_dir.replace(base_dir_len, wcstring::npos, name_str);

                int stat_res = wstat(new_dir, &buf);

                if (!stat_res)
                {
                    // Insert a "file ID" into visited_files
                    // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                    // If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
                    const file_id_t file_id = file_id_t::file_id_from_stat(&buf);
                    if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
                    {
                        new_dir.push_back(L'/');

                        /*
                          Regular matching
                        */
                        if (whole_match)
                        {
                            const wchar_t *new_wc = L"";
                            if (next_slash)
                            {
                                new_wc=next_slash+1;
                                /*
                                  Accept multiple '/' as a single directory separator
                                */
                                while (*new_wc==L'/')
                                {
                                    new_wc++;
                                }
                            }

                            new_res = wildcard_expand_internal(new_wc,
                                                               new_dir.c_str(),
                                                               flags,
                                                               out,
                                                               completion_set,
                                                               visited_files);

                            if (new_res == -1)
                            {
                                res = -1;
                                break;
                            }
                            res |= new_res;

                        }

                        /*
                          Recursive matching
                        */
                        if (partial_match)
                        {

                            new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
                                                               new_dir.c_str(),
                                                               flags | WILDCARD_RECURSIVE,
                                                               out,
                                                               completion_set,
                                                               visited_files);

                            if (new_res == -1)
                            {
                                res = -1;
                                break;
                            }
                            res |= new_res;

                        }
                    }
                }
            }
        }
    }
    closedir(dir);

    return res;
}
// static
void AIStateMachine::setMaxCount(F32 StateMachineMaxTime)
{
  llassert(is_main_thread());
  Dout(dc::statemachine, "(Re)calculating AIStateMachine::sMaxCount");
  sMaxCount = calc_clock_frequency() * StateMachineMaxTime / 1000;
}
void AIStateMachine::finish(void)
{
  DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]");
  mSetStateLock.lock();
  llassert(mState == bs_run || mState == bs_abort);
  // It is possible that mIdle is true when abort or finish was called from
  // outside multiplex_impl. However, that only may be done by the main thread.
  llassert(!mIdle || is_main_thread());
  if (!mIdle)
	idle();					// After calling this, we don't want other threads to call set_state() anymore.
  mState = bs_finish;		// Causes additional calls to set_state to be ignored.
  mSetStateLock.unlock();
  finish_impl();
  // Did finish_impl call kill()? Then that is only the default. Remember it.
  bool default_delete = (mState == bs_killed);
  mState = bs_finish;
  if (mParent)
  {
	// It is possible that the parent is not running when the parent is in fact aborting and called
	// abort on this object from it's abort_impl function. It that case we don't want to recursively
	// call abort again (or change it's state).
	if (mParent->running())
	{
	  if (mAborted && mAbortParent)
	  {
		mParent->abort();
		mParent = NULL;
	  }
	  else if (!mAborted || mOnAbortSignalParent)
	  {
		mParent->set_state(mNewParentState);
	  }
	}
  }
  // After this (bool)*this evaluates to true and we can call the callback, which then is allowed to call run().
  mState = bs_callback;
  if (mCallback)
  {
	// This can/may call kill() that sets mState to bs_kill and in which case the whole AIStateMachine
	// will be deleted from the mainloop, or it may call run() that sets mState is set to bs_initialize
	// and might change or reuse mCallback or mParent.
	mCallback->callback(!mAborted);
	if (mState != bs_initialize)
	{
	  delete mCallback;
	  mCallback = NULL;
	  mParent = NULL;
	}
  }
  else
  {
	// Not restarted by callback. Allow run() to be called later on.
	mParent = NULL;
  }
  // Fix the final state.
  if (mState == bs_callback)
	mState = default_delete ? bs_killed : bs_initialize;
  if (mState == bs_killed && mActive == as_idle)
  {
	// Bump the statemachine onto the active statemachine list, or else it won't be deleted.
	mSetStateLock.lock();
	locked_cont();
	idle();
  }
}
void AIStateMachine::set_state(state_type state)
{
  DoutEntering(dc::statemachine, "AIStateMachine::set_state(" << state_str(state) << ") [" << (void*)this << "]");

  // Stop race condition of multiple threads calling cont() or set_state() here.
  mSetStateLock.lock();

  // Do not call set_state() unless running.
  llassert(mState == bs_run || !is_main_thread());

  // If this function is called from another thread than the main thread, then we have to ignore
  // it if we're not idle and the state is less than the current state. The main thread must
  // be able to change the state to anything (also smaller values). Note that that only can work
  // if the main thread itself at all times cancels thread callbacks that call set_state()
  // before calling idle() again!
  //
  // Thus: main thead calls idle(), and tells one or more threads to do callbacks on events,
  // which (might) call set_state(). If the main thread calls set_state first (currently only
  // possible as a result of the use of a timer) it will set mIdle to false (here) then cancel
  // the call backs from the other threads and only then call idle() again.
  // Thus if you want other threads get here while mIdle is false to be ignored then the
  // main thread should use a large value for the new run state.
  //
  // If a non-main thread calls set_state first, then the state is changed but the main thread
  // can still override it if it calls set_state before handling the new state; in the latter
  // case it would still be as if the call from the non-main thread was ignored.
  //
  // Concurrent calls from non-main threads however, always result in the largest state
  // to prevail.

  // If the state machine is already running, and we are not the main-thread and the new
  // state is less than the current state, ignore it.
  // Also, if abort() or finish() was called, then we should just ignore it.
  if (mState != bs_run ||
	  (!mIdle && state <= mRunState && !AIThreadID::in_main_thread()))
  {
#ifdef SHOW_ASSERT
	// It's a bit weird if the same thread does two calls on a row where the second call
	// has a smaller value: warn about that.
	if (mState == bs_run && mContThread.equals_current_thread())
	{
	  llwarns << "Ignoring call to set_state(" << state_str(state) <<
		  ") by non-main thread before main-thread could react on previous call, "
		  "because new state is smaller than old state (" << state_str(mRunState) << ")." << llendl;
	}
#endif
	mSetStateLock.unlock();
	return;		// Ignore.
  }

  // Do not call idle() when set_state is called from another thread; use idle(state_type) instead.
  llassert(!mCalledThreadUnsafeIdle || is_main_thread());

  // Change mRunState to the requested value.
  if (mRunState != state)
  {
	mRunState = state;
	Dout(dc::statemachine, "mRunState set to " << state_str(mRunState));
  }

  // Continue the state machine if appropriate.
  if (mIdle)
	locked_cont();				// This unlocks mSetStateLock.
  else
	mSetStateLock.unlock();

  // If we get here then mIdle is false, so only mRunState can still be changed but we won't
  // call locked_cont() anymore. When the main thread finally picks up on the state change,
  // it will cancel any possible callbacks from other threads and process the largest state
  // that this function was called with in the meantime.
}
示例#25
0
int main() 
{
  is_main_thread();
  std::thread th (is_main_thread);
  th.join();
}
示例#26
0
	void ensure_main_thread() {
		if (!is_main_thread()) uBugCheck();
	}
示例#27
0
文件: env.cpp 项目: lnsoso/fish-shell
env_var_t env_get_string(const wcstring &key, env_mode_flags_t mode)
{
    const bool has_scope = mode & (ENV_LOCAL | ENV_GLOBAL | ENV_UNIVERSAL);
    const bool search_local = !has_scope || (mode & ENV_LOCAL);
    const bool search_global = !has_scope || (mode & ENV_GLOBAL);
    const bool search_universal = !has_scope || (mode & ENV_UNIVERSAL);

    const bool search_exported = (mode & ENV_EXPORT) || !(mode & ENV_UNEXPORT);
    const bool search_unexported = (mode & ENV_UNEXPORT) || !(mode & ENV_EXPORT);

    /* Make the assumption that electric keys can't be shadowed elsewhere, since we currently block that in env_set() */
    if (is_electric(key))
    {
        if (!search_global) return env_var_t::missing_var();
        /* Big hack...we only allow getting the history on the main thread. Note that history_t may ask for an environment variable, so don't take the lock here (we don't need it) */
        if (key == L"history" && is_main_thread())
        {
            env_var_t result;

            history_t *history = reader_get_history();
            if (! history)
            {
                history = &history_t::history_with_name(L"fish");
            }
            if (history)
                history->get_string_representation(&result, ARRAY_SEP_STR);
            return result;
        }
        else if (key == L"COLUMNS")
        {
            return to_string(common_get_width());
        }
        else if (key == L"LINES")
        {
            return to_string(common_get_height());
        }
        else if (key == L"status")
        {
            return to_string(proc_get_last_status());
        }
        else if (key == L"umask")
        {
            return format_string(L"0%0.3o", get_umask());
        }
        // we should never get here unless the electric var list is out of sync
    }

    if (search_local || search_global) {
        /* Lock around a local region */
        scoped_lock lock(env_lock);

        env_node_t *env = search_local ? top : global_env;

        while (env != NULL)
        {
            const var_entry_t *entry = env->find_entry(key);
            if (entry != NULL && (entry->exportv ? search_exported : search_unexported))
            {
                if (entry->val == ENV_NULL)
                {
                    return env_var_t::missing_var();
                }
                else
                {
                    return entry->val;
                }
            }

            if (has_scope)
            {
                if (!search_global || env == global_env) break;
                env = global_env;
            }
            else
            {
                env = env->next_scope_to_search();
            }
        }
    }

    if (!search_universal) return env_var_t::missing_var();

    /* Another big hack - only do a universal barrier on the main thread (since it can change variable values)
        Make sure we do this outside the env_lock because it may itself call env_get_string */
    if (is_main_thread() && ! get_proc_had_barrier())
    {
        set_proc_had_barrier(true);
        env_universal_barrier();
    }

    if (uvars())
    {
        env_var_t env_var = uvars()->get(key);
        if (env_var == ENV_NULL || !(uvars()->get_export(key) ? search_exported : search_unexported))
        {
            env_var = env_var_t::missing_var();
        }
        return env_var;
    }
    return env_var_t::missing_var();
}
示例#28
0
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards.

   Because this function calls itself recursively with substrings,
   it's important that the parameters be raw pointers instead of wcstring,
   which would be too expensive to construct for all substrings.
 */
static int wildcard_expand_internal(const wchar_t *wc,
                                    const wchar_t *base_dir,
                                    expand_flags_t flags,
                                    std::vector<completion_t> &out,
                                    std::set<wcstring> &completion_set,
                                    std::set<file_id_t> &visited_files
                                   )
{

    /* Points to the end of the current wildcard segment */
    const wchar_t *wc_end;

    /* Variables for traversing a directory */
    DIR *dir;

    /* The result returned */
    int res = 0;

    /* Length of the directory to search in */
    size_t base_len;

    /* Variables for testing for presense of recursive wildcards */
    const wchar_t *wc_recursive;
    bool is_recursive;

    /* Slightly mangled version of base_dir */
    const wchar_t *dir_string;

    //  debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

    if (is_main_thread() ? reader_interrupted() : reader_thread_job_is_stale())
    {
        return -1;
    }

    if (!wc || !base_dir)
    {
        debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
        return 0;
    }

    if (flags & ACCEPT_INCOMPLETE)
    {
        /*
           Avoid excessive number of returned matches for wc ending with a *
        */
        size_t len = wcslen(wc);
        if (len && (wc[len-1]==ANY_STRING))
        {
            wchar_t * foo = wcsdup(wc);
            foo[len-1]=0;
            int res = wildcard_expand_internal(foo, base_dir, flags, out, completion_set, visited_files);
            free(foo);
            return res;
        }
    }

    /*
      Initialize various variables
    */

    dir_string = base_dir[0]==L'\0'?L".":base_dir;

    if (!(dir = wopendir(dir_string)))
    {
        return 0;
    }

    wc_end = wcschr(wc,L'/');
    base_len = wcslen(base_dir);

    /*
      Test for recursive match string in current segment
    */
    wc_recursive = wcschr(wc, ANY_STRING_RECURSIVE);
    is_recursive = (wc_recursive && (!wc_end || wc_recursive < wc_end));

    /*
      Is this segment of the wildcard the last?
    */
    if (!wc_end)
    {
        /*
          Wildcard segment is the last segment,

          Insert all matching files/directories
        */
        if (wc[0]=='\0')
        {
            /*
              The last wildcard segment is empty. Insert everything if
              completing, the directory itself otherwise.
            */
            if (flags & ACCEPT_INCOMPLETE)
            {
                wcstring next;
                while (wreaddir(dir, next))
                {
                    if (next[0] != L'.')
                    {
                        wcstring long_name = make_path(base_dir, next);

                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out,
                                                         long_name,
                                                         next,
                                                         L"",
                                                         flags);
                        }
                    }
                }
            }
            else
            {
                res = 1;
                insert_completion_if_missing(base_dir, out, completion_set);
            }
        }
        else
        {
            /*
              This is the last wildcard segment, and it is not empty. Match files/directories.
            */
            wcstring next;
            while (wreaddir(dir, next))
            {
                const wchar_t * const name = next.c_str();
                if (flags & ACCEPT_INCOMPLETE)
                {

                    const wcstring long_name = make_path(base_dir, next);

                    /*
                      Test for matches before stating file, so as to minimize the number of calls to the much slower stat function
                    */
                    std::vector<completion_t> test;
                    if (wildcard_complete(name,
                                          wc,
                                          L"",
                                          0,
                                          test,
                                          0))
                    {
                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out,
                                                         long_name,
                                                         name,
                                                         wc,
                                                         flags);

                        }
                    }
                }
                else
                {
                    if (wildcard_match2(name, wc, true))
                    {
                        const wcstring long_name = make_path(base_dir, next);
                        int skip = 0;

                        if (is_recursive)
                        {
                            /*
                              In recursive mode, we are only
                              interested in adding files -directories
                              will be added in the next pass.
                            */
                            struct stat buf;
                            if (!wstat(long_name, &buf))
                            {
                                skip = S_ISDIR(buf.st_mode);
                            }
                        }
                        if (! skip)
                        {
                            insert_completion_if_missing(long_name, out, completion_set);
                        }
                        res = 1;
                    }
                }
            }
        }
    }

    if (wc_end || is_recursive)
    {
        /*
          Wilcard segment is not the last segment.  Recursively call
          wildcard_expand for all matching subdirectories.
        */

        /*
          wc_str is the part of the wildcarded string from the
          beginning to the first slash
        */
        wchar_t *wc_str;

        /*
          new_dir is a scratch area containing the full path to a
          file/directory we are iterating over
        */
        wchar_t *new_dir;

        /*
          The maximum length of a file element
        */
        long ln=MAX_FILE_LENGTH;
        char * narrow_dir_string = wcs2str(dir_string);

        /*
          In recursive mode, we look through the directory twice. If
          so, this rewind is needed.
        */
        rewinddir(dir);

        if (narrow_dir_string)
        {
            /*
               Find out how long the filename can be in a worst case
               scenario
            */
            ln = pathconf(narrow_dir_string, _PC_NAME_MAX);

            /*
              If not specified, use som large number as fallback
            */
            if (ln < 0)
                ln = MAX_FILE_LENGTH;
            free(narrow_dir_string);
        }
        new_dir= (wchar_t *)malloc(sizeof(wchar_t)*(base_len+ln+2));

        wc_str = wc_end?wcsndup(wc, wc_end-wc):wcsdup(wc);

        if ((!new_dir) || (!wc_str))
        {
            DIE_MEM();
        }

        wcscpy(new_dir, base_dir);

        wcstring next;
        while (wreaddir(dir, next))
        {
            const wchar_t *name = next.c_str();

            /*
              Test if the file/directory name matches the whole
              wildcard element, i.e. regular matching.
            */
            int whole_match = wildcard_match2(name, wc_str, true);
            int partial_match = 0;

            /*
               If we are doing recursive matching, also check if this
               directory matches the part up to the recusrive
               wildcard, if so, then we can search all subdirectories
               for matches.
            */
            if (is_recursive)
            {
                const wchar_t *end = wcschr(wc, ANY_STRING_RECURSIVE);
                wchar_t *wc_sub = wcsndup(wc, end-wc+1);
                partial_match = wildcard_match2(name, wc_sub, true);
                free(wc_sub);
            }

            if (whole_match || partial_match)
            {
                struct stat buf;
                char *dir_str;
                int stat_res;
                int new_res;

                wcscpy(&new_dir[base_len], name);
                dir_str = wcs2str(new_dir);

                if (dir_str)
                {
                    stat_res = stat(dir_str, &buf);
                    free(dir_str);

                    if (!stat_res)
                    {
                        // Insert a "file ID" into visited_files
                        // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                        // If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
                        const file_id_t file_id(buf.st_dev, buf.st_ino);
                        if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
                        {
                            size_t new_len = wcslen(new_dir);
                            new_dir[new_len] = L'/';
                            new_dir[new_len+1] = L'\0';

                            /*
                              Regular matching
                            */
                            if (whole_match)
                            {
                                const wchar_t *new_wc = L"";
                                if (wc_end)
                                {
                                    new_wc=wc_end+1;
                                    /*
                                      Accept multiple '/' as a single direcotry separator
                                    */
                                    while (*new_wc==L'/')
                                    {
                                        new_wc++;
                                    }
                                }

                                new_res = wildcard_expand_internal(new_wc,
                                                                   new_dir,
                                                                   flags,
                                                                   out,
                                                                   completion_set,
                                                                   visited_files);

                                if (new_res == -1)
                                {
                                    res = -1;
                                    break;
                                }
                                res |= new_res;

                            }

                            /*
                              Recursive matching
                            */
                            if (partial_match)
                            {

                                new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
                                                                   new_dir,
                                                                   flags | WILDCARD_RECURSIVE,
                                                                   out,
                                                                   completion_set,
                                                                   visited_files);

                                if (new_res == -1)
                                {
                                    res = -1;
                                    break;
                                }
                                res |= new_res;

                            }
                        }
                    }
                }
            }
        }

        free(wc_str);
        free(new_dir);
    }
    closedir(dir);

    return res;
}
示例#29
0
// Exit the current process.  Does not return.
// An exited process remains in the zombie state
// until its parent calls wait() to find out it exited.
void
exit(void)
{
    struct proc *p;
    int fd;
    int rmBrothers=0;

    if(!is_main_thread(proc)) {
        // Kill main thread
        proc->parent->killed=1;
        if(proc->parent->state==SLEEPING)
            proc->parent->state=RUNNABLE;
        //clear_thread(proc);
        rmBrothers=1;
        //return;
    }

    if(proc == initproc)
        panic("init exiting");

    cprintf("#");
    //release(&ptable.lock);
    if(!holding(&ptable.lock)) {
        cprintf("[ex%d]", proc->pid);
        acquire(&ptable.lock);
    }
    cprintf("%");

    // Pass abandoned proc children to init &
    // kill all threads beneath (children who are not procs)
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
        if(p->parent == proc) {
            if(is_main_thread(p) && rmBrothers==0) {
                p->parent = initproc;
                if(p->state == ZOMBIE)
                    wakeup1(initproc);
            } else {
                clear_thread(p);
            }
        }
    }

    if(rmBrothers)
        goto end;

    // Close all open files.
    for(fd = 0; fd < NOFILE; fd++) {
        if(proc->ofile[fd]) {
            fileclose(proc->ofile[fd]);
            proc->ofile[fd] = 0;
        }
    }

    iput(proc->cwd);
    proc->cwd = 0;

end:
    // Parent might be sleeping in wait().
    wakeup1(proc->parent);

    // Jump into the scheduler, never to return.
    proc->state = ZOMBIE;
    sched();
    panic("zombie exit");
}
示例#30
0
env_var_t env_get_string(const wcstring &key)
{
    /* Big hack...we only allow getting the history on the main thread. Note that history_t may ask for an environment variable, so don't take the lock here (we don't need it) */
    const bool is_main = is_main_thread();
    if (key == L"history" && is_main)
    {
        env_var_t result;

        history_t *history = reader_get_history();
        if (! history)
        {
            history = &history_t::history_with_name(L"fish");
        }
        if (history)
            history->get_string_representation(result, ARRAY_SEP_STR);
        return result;
    }
    else if (key == L"COLUMNS")
    {
        return to_string(common_get_width());
    }
    else if (key == L"LINES")
    {
        return to_string(common_get_height());
    }
    else if (key == L"status")
    {
        return to_string(proc_get_last_status());
    }
    else if (key == L"umask")
    {
        return format_string(L"0%0.3o", get_umask());
    }
    else
    {
        {
            /* Lock around a local region */
            scoped_lock lock(env_lock);

            env_node_t *env = top;
            wcstring result;

            while (env != NULL)
            {
                const var_entry_t *entry = env->find_entry(key);
                if (entry != NULL)
                {
                    if (entry->val == ENV_NULL)
                    {
                        return env_var_t::missing_var();
                    }
                    else
                    {
                        return entry->val;
                    }
                }

                env = env->next_scope_to_search();
            }
        }

        /* Another big hack - only do a universal barrier on the main thread (since it can change variable values)
           Make sure we do this outside the env_lock because it may itself call env_get_string */
        if (is_main && ! get_proc_had_barrier())
        {
            set_proc_had_barrier(true);
            env_universal_barrier();
        }

        const wchar_t *item = env_universal_get(key);

        if (!item || (wcscmp(item, ENV_NULL)==0))
        {
            return env_var_t::missing_var();
        }
        else
        {
            return item;
        }
    }
}