<commit_before>/**
 * \file
 * \brief Slot allocator for two level CSpace
 */

/*
 * Copyright (c) 2016, ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
 */

#include <barrelfish/barrelfish.h>
#include <barrelfish/core_state.h>
#include "internal.h"
#include "../../newlib/newlib/libc/include/stdlib.h"

/**
 * \brief slot allocator
 *
 * \param ca   Instance of the allocator
 * \param ret  Pointer to return the allocated slot
 */
errval_t two_level_alloc(struct slot_allocator *ca, struct capref *ret)
{
    errval_t err = SYS_ERR_OK;
    struct multi_slot_allocator *mca = (struct multi_slot_allocator*)ca;

    thread_mutex_lock(&ca->mutex);
    assert(ca->space != 0);
    ca->space--;

    /* Try allocating from the list of single slot allocators */
    struct slot_allocator_list *walk = mca->head;
    //struct slot_allocator_list *prev = NULL;
    while(walk != NULL) {
        err = walk->a.a.alloc(&walk->a.a, ret);
        if (err_no(err) != LIB_ERR_SLOT_ALLOC_NO_SPACE) {
            break;
        }
        //prev = walk;
        walk = walk->next;
    }
    if (err_is_fail(err)) {
        return err_push(err, LIB_ERR_SINGLE_SLOT_ALLOC);
    }

    /* If no more slots left, grow */
    if (ca->space == 0) {
        ca->space = ca->nslots;
        /* Pull in the reserve */
        mca->reserve->next = mca->head;
        mca->head = mca->reserve;

        /* Setup a new reserve */
        // Cnode: in Root CN
        struct capref cap;
        struct cnoderef cnode;
        thread_mutex_unlock(&ca->mutex);
        // Do not call slot_alloc_root() here as we want control over refill.
        struct slot_alloc_state *state = get_slot_alloc_state();
        struct slot_allocator *rca = (struct slot_allocator *)(&state->rootca);
        err = rca->alloc(rca, &cap);
        // From here: we may call back into slot_alloc when resizing root
        // cnode and/or creating new L2 Cnode.
        if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) {
            // resize root slot allocator (and rootcn)
            err = root_slot_allocator_refill(NULL, NULL);
            if (err_is_fail(err)) {
                return err_push(err, LIB_ERR_ROOTSA_RESIZE);
            }
            err = rca->alloc(rca, &cap);<commit_msg>libbarrelfish: two_level_alloc: Unlock mutex when we error out early.<commit_after>/**
 * \file
 * \brief Slot allocator for two level CSpace
 */

/*
 * Copyright (c) 2016, ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
 */

#include <barrelfish/barrelfish.h>
#include <barrelfish/core_state.h>
#include "internal.h"
#include "../../newlib/newlib/libc/include/stdlib.h"

/**
 * \brief slot allocator
 *
 * \param ca   Instance of the allocator
 * \param ret  Pointer to return the allocated slot
 */
errval_t two_level_alloc(struct slot_allocator *ca, struct capref *ret)
{
    errval_t err = SYS_ERR_OK;
    struct multi_slot_allocator *mca = (struct multi_slot_allocator*)ca;

    thread_mutex_lock(&ca->mutex);
    assert(ca->space != 0);
    ca->space--;

    /* Try allocating from the list of single slot allocators */
    struct slot_allocator_list *walk = mca->head;
    //struct slot_allocator_list *prev = NULL;
    while(walk != NULL) {
        err = walk->a.a.alloc(&walk->a.a, ret);
        if (err_no(err) != LIB_ERR_SLOT_ALLOC_NO_SPACE) {
            break;
        }
        //prev = walk;
        walk = walk->next;
    }
    if (err_is_fail(err)) {
        thread_mutex_unlock(&ca->mutex);
        return err_push(err, LIB_ERR_SINGLE_SLOT_ALLOC);
    }

    /* If no more slots left, grow */
    if (ca->space == 0) {
        ca->space = ca->nslots;
        /* Pull in the reserve */
        mca->reserve->next = mca->head;
        mca->head = mca->reserve;

        /* Setup a new reserve */
        // Cnode: in Root CN
        struct capref cap;
        struct cnoderef cnode;
        thread_mutex_unlock(&ca->mutex);
        // Do not call slot_alloc_root() here as we want control over refill.
        struct slot_alloc_state *state = get_slot_alloc_state();
        struct slot_allocator *rca = (struct slot_allocator *)(&state->rootca);
        err = rca->alloc(rca, &cap);
        // From here: we may call back into slot_alloc when resizing root
        // cnode and/or creating new L2 Cnode.
        if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) {
            // resize root slot allocator (and rootcn)
            err = root_slot_allocator_refill(NULL, NULL);
            if (err_is_fail(err)) {
                return err_push(err, LIB_ERR_ROOTSA_RESIZE);
            }
            err = rca->alloc(rca, &cap);
{'fraction_non_alphanumeric': 0.11789347695990425, 'fraction_numerical': 0.0047875523638539795, 'mean_word_length': 2.453168044077135, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3010184', 'n_tokens_mistral': 1678, 'n_tokens_neox': 1635, 'n_words': 462}