Ejemplo n.º 1
0
int _DkMutexLockTimeout (struct mutex_handle * m, PAL_NUM timeout)
{
    int i, ret = 0;
#ifdef DEBUG_MUTEX
    int tid = INLINE_SYSCALL(gettid, 0);
#endif
    /* If this is a trylock-style call, break more quickly. */
    int iterations = (timeout == 0) ? 1 : MUTEX_SPINLOCK_TIMES;

    /* Spin and try to take lock.  Ignore any contribution this makes toward
     * the timeout.*/
    for (i = 0; i < iterations; i++) {
        if (MUTEX_UNLOCKED == cmpxchg(&m->locked, MUTEX_UNLOCKED, MUTEX_LOCKED))
            goto success;
        CPU_RELAX();
    }

    if (timeout == 0) {
        ret = -PAL_ERROR_TRYAGAIN;
        goto out;
    }

    // Bump up the waiters count; we are probably going to block
    atomic_inc(&m->nwaiters);

    while (MUTEX_LOCKED == cmpxchg(&m->locked, MUTEX_UNLOCKED, MUTEX_LOCKED)) {
        struct timespec waittime, *waittimep = NULL;
        if (timeout != NO_TIMEOUT) {
            long sec = timeout / 1000000;
            long microsec = timeout - (sec * 1000000);
            waittime.tv_sec = sec;
            waittime.tv_nsec = microsec * 1000;
            waittimep = &waittime;
        }

        ret = INLINE_SYSCALL(futex, 6, m, FUTEX_WAIT, MUTEX_LOCKED, waittimep, NULL, 0);

        if (IS_ERR(ret)) {
            if (ERRNO(ret) == EWOULDBLOCK) {
                if (timeout != NO_TIMEOUT) {
                    ret = -PAL_ERROR_TRYAGAIN;
                    atomic_dec(&m->nwaiters);
                    goto out;
                }
            } else {
#ifdef DEBUG_MUTEX
                printf("futex failed (err = %d)\n", ERRNO(ret));
#endif
                ret = unix_to_pal_error(ERRNO(ret));
                atomic_dec(&m->nwaiters);
                goto out;
            }
        }
    }

    atomic_dec(&m->nwaiters);

success:
#ifdef DEBUG_MUTEX
    m->owner = tid;
#endif
    ret = 0;
out:

#ifdef DEBUG_MUTEX
    if (ret < 0)
        printf("mutex failed (%s, tid = %d)\n", PAL_STRERROR(ret), tid);
#endif
    return ret;
}
Ejemplo n.º 2
0
void pal_main (PAL_NUM pal_token, void * pal_addr,
               const char * pal_name,
               int argc, const char ** argv, const char ** envp,
               PAL_HANDLE parent_handle,
               PAL_HANDLE thread_handle,
               PAL_HANDLE exec_handle,
               PAL_HANDLE manifest_handle)
{
    int ret;
    bool is_parent = !parent_handle;

#if PROFILING == 1
    __pal_control.host_specific_startup_time =
            _DkSystemTimeQuery() - pal_state.start_time;
#endif

    pal_state.pal_token     = pal_token;
    pal_state.pal_addr      = pal_addr;
    pal_state.parent_handle = parent_handle;
    pal_state.pagesize      = _DkGetPagesize();
    pal_state.alloc_align   = _DkGetAllocationAlignment();
    pal_state.alloc_shift   = pal_state.alloc_align - 1;
    pal_state.alloc_mask    = ~pal_state.alloc_shift;

    init_slab_mgr(pal_state.alloc_align);

    char * exec = NULL, * manifest = NULL;

    if (exec_handle) {
        exec = __alloca(URI_MAX);
        ret = _DkStreamGetName(exec_handle, exec, URI_MAX);
        if (ret < 0)
            init_fail(-ret, "cannot get executable name");
    }

    if (manifest_handle) {
        manifest = __alloca(URI_MAX);
        ret = _DkStreamGetName(manifest_handle, manifest, URI_MAX);
        if (ret < 0)
            init_fail(-ret, "cannot get manifest name");
    } else {
        if (is_parent) {
#if PROFILING == 1
            unsigned long before_find_manifest = _DkSystemTimeQuery();
#endif
            do {
                if (exec_handle) {
                    assert(!!exec);
                    /* try open "<exec>.manifest" */
                    manifest = __alloca(URI_MAX);
                    snprintf(manifest, URI_MAX, "%s.manifest", exec);
                    ret = _DkStreamOpen(&manifest_handle,
                                        manifest,
                                        PAL_ACCESS_RDONLY, 0, 0, 0);
                    if (!ret)
                        break;
                }

                /* try open "file:manifest" */
                manifest = "file:manifest";
                ret = _DkStreamOpen(&manifest_handle,
                                    manifest,
                                    PAL_ACCESS_RDONLY, 0, 0, 0);
                if (!ret)
                    break;

                /* well, there is no manifest file, leave it alone */
                if (!manifest_handle)
                    printf("Can't fine any manifest, will run without one\n");
            } while (0);

#if PROFILING == 1
            pal_state.manifest_loading_time +=
                            _DkSystemTimeQuery() - before_find_manifest;
#endif
        }
    }

    /* load manifest if there is one */
    if (manifest_handle) {
#if PROFILING == 1
        unsigned long before_load_manifest = _DkSystemTimeQuery();
#endif

        PAL_STREAM_ATTR attr;
        ret = _DkStreamAttributesQuerybyHandle(manifest_handle, &attr);
        if (ret < 0)
            init_fail(-ret, "cannot open manifest file");

        void * cfg_addr = NULL;
        int cfg_size = attr.pending_size;

        ret = _DkStreamMap(manifest_handle, &cfg_addr,
                           PAL_PROT_READ, 0,
                           ALLOC_ALIGNUP(cfg_size));
        if (ret < 0)
            init_fail(-ret, "cannot open manifest file");

        struct config_store * root_config = malloc(sizeof(struct config_store));
        root_config->raw_data = cfg_addr;
        root_config->raw_size = cfg_size;
        root_config->malloc = malloc;
        root_config->free = free;

        const char * errstring = NULL;
        if ((ret = read_config(root_config, loader_filter, &errstring)) < 0)
            init_fail(-ret, errstring);

        pal_state.root_config = root_config;

#if PROFILING == 1
        pal_state.manifest_loading_time +=
                        _DkSystemTimeQuery() - before_load_manifest;
#endif
    }

    /* if there is no executable, try to find one in the manifest */
    if (is_parent && !exec_handle) {
        exec = __alloca(URI_MAX);
        assert(!!pal_state.root_config);

        ret = get_config(pal_state.root_config, "loader.exec", exec, URI_MAX);
        if (ret > 0) {
            ret = _DkStreamOpen(&exec_handle, exec, PAL_ACCESS_RDONLY,
                                0, 0, 0);
            if (ret < 0)
                init_fail(-ret, "cannot open executable");

            /* must be a ELF */
            if (check_elf_object(exec_handle) < 0)
                init_fail(PAL_ERROR_INVAL, "executable is not a ELF binary");
        } else {
            exec = NULL;
        }
    }

    if (is_parent && !exec_handle && !manifest_handle) {
        printf("USAGE: %s [executable|manifest] args ...\n", pal_name);
        _DkProcessExit(0);
        return;
    }

    pal_state.manifest        = manifest;
    pal_state.manifest_handle = manifest_handle;
    pal_state.exec            = exec;
    pal_state.exec_handle     = exec_handle;

    const char * first_argv = *argv;
    argc--;
    argv++;

    if (is_parent && exec_handle) {
        first_argv = exec;
        if (pal_state.root_config) {
            char cfgbuf[CONFIG_MAX];
            ret = get_config(pal_state.root_config, "loader.execname", cfgbuf,
                             CONFIG_MAX);
            if (ret > 0)
                first_argv = remalloc(cfgbuf, ret + 1);
        }
    }

    if (pal_state.root_config)
        load_libraries();

    if (exec_handle) {
#if PROFILING == 1
        unsigned long before_load_exec = _DkSystemTimeQuery();
#endif

        ret = load_elf_object_by_handle(exec_handle, OBJECT_EXEC);
        if (ret < 0)
            init_fail(ret, PAL_STRERROR(ret));

#if PROFILING == 1
        pal_state.linking_time += _DkSystemTimeQuery() - before_load_exec;
#endif
    }

#if PROFILING == 1
    unsigned long before_tail = _DkSystemTimeQuery();
#endif

    if (pal_state.root_config) {
        read_envs(&envp);
        set_debug_type();
        set_syscall_symbol();
    }

    __pal_control.process_id         = _DkGetProcessId();
    __pal_control.host_id            = _DkGetHostId();
    __pal_control.manifest_handle    = manifest_handle;
    __pal_control.executable         = exec;
    __pal_control.parent_process     = parent_handle;
    __pal_control.first_thread       = thread_handle;

    _DkGetAvailableUserAddressRange(&__pal_control.user_address.start,
                                    &__pal_control.user_address.end);

    __pal_control.pagesize           = pal_state.pagesize;
    __pal_control.alloc_align        = pal_state.alloc_align;
    __pal_control.broadcast_stream   = _DkBroadcastStreamOpen();

    _DkGetCPUInfo(&__pal_control.cpu_info);
    __pal_control.mem_info.mem_total = _DkMemoryQuota();

#if PROFILING == 1
    pal_state.tail_startup_time      += _DkSystemTimeQuery() - before_tail;

    __pal_control.relocation_time     = pal_state.relocation_time;
    __pal_control.linking_time        = pal_state.linking_time;
    __pal_control.manifest_loading_time
                                      = pal_state.manifest_loading_time;
    __pal_control.allocation_time     = pal_state.slab_time;
    __pal_control.child_creation_time = is_parent ? 0 : pal_state.start_time -
                                        pal_state.process_create_time;
#endif

    /* Now we will start the execution */
    start_execution(first_argv, argc, argv, envp);

    /* We wish we will never reached here */
    init_fail(PAL_ERROR_DENIED, "unexpected termination");
}