Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 Wind River Systems, Inc.
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : #include <kernel.h>
8 : : #include <kernel_structs.h>
9 : :
10 : : #include <toolchain.h>
11 : : #include <linker/sections.h>
12 : : #include <wait_q.h>
13 : : #include <sys/dlist.h>
14 : : #include <ksched.h>
15 : : #include <init.h>
16 : : #include <sys/check.h>
17 : :
18 : : /**
19 : : * @brief Initialize kernel memory slab subsystem.
20 : : *
21 : : * Perform any initialization of memory slabs that wasn't done at build time.
22 : : * Currently this just involves creating the list of free blocks for each slab.
23 : : *
24 : : * @retval 0 on success.
25 : : * @retval -EINVAL if @p slab contains invalid configuration and/or values.
26 : : */
27 : 1 : static int create_free_list(struct k_mem_slab *slab)
28 : : {
29 : : uint32_t j;
30 : : char *p;
31 : :
32 : : /* blocks must be word aligned */
33 [ - + ]: 1 : CHECKIF(((slab->block_size | (uintptr_t)slab->buffer) &
34 : : (sizeof(void *) - 1)) != 0U) {
35 : 0 : return -EINVAL;
36 : : }
37 : :
38 : 1 : slab->free_list = NULL;
39 : 1 : p = slab->buffer;
40 : :
41 [ + + ]: 65 : for (j = 0U; j < slab->num_blocks; j++) {
42 : 64 : *(char **)p = slab->free_list;
43 : 64 : slab->free_list = p;
44 : 64 : p += slab->block_size;
45 : : }
46 : 1 : return 0;
47 : : }
48 : :
49 : : /**
50 : : * @brief Complete initialization of statically defined memory slabs.
51 : : *
52 : : * Perform any initialization that wasn't done at build time.
53 : : *
54 : : * @return 0 on success, fails otherwise.
55 : : */
56 : 1 : static int init_mem_slab_module(const struct device *dev)
57 : : {
58 : 1 : int rc = 0;
59 : : ARG_UNUSED(dev);
60 : :
61 [ - + - + ]: 1 : STRUCT_SECTION_FOREACH(k_mem_slab, slab) {
62 : 0 : rc = create_free_list(slab);
63 [ # # ]: 0 : if (rc < 0) {
64 : 0 : goto out;
65 : : }
66 : 0 : z_object_init(slab);
67 : : }
68 : :
69 : 1 : out:
70 : 1 : return rc;
71 : : }
72 : :
73 : : SYS_INIT(init_mem_slab_module, PRE_KERNEL_1,
74 : : CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
75 : :
76 : 1 : int k_mem_slab_init(struct k_mem_slab *slab, void *buffer,
77 : : size_t block_size, uint32_t num_blocks)
78 : : {
79 : 1 : int rc = 0;
80 : :
81 : 1 : slab->num_blocks = num_blocks;
82 : 1 : slab->block_size = block_size;
83 : 1 : slab->buffer = buffer;
84 : 1 : slab->num_used = 0U;
85 : 1 : slab->lock = (struct k_spinlock) {};
86 : :
87 : : #ifdef CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION
88 : : slab->max_used = 0U;
89 : : #endif
90 : :
91 : 1 : rc = create_free_list(slab);
92 [ - + ]: 1 : if (rc < 0) {
93 : 0 : goto out;
94 : : }
95 : :
96 : 1 : z_waitq_init(&slab->wait_q);
97 : 1 : z_object_init(slab);
98 : 1 : out:
99 : : SYS_PORT_TRACING_OBJ_INIT(k_mem_slab, slab, rc);
100 : :
101 : 1 : return rc;
102 : : }
103 : :
104 : 0 : int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, k_timeout_t timeout)
105 : : {
106 : 0 : k_spinlock_key_t key = k_spin_lock(&slab->lock);
107 : : int result;
108 : :
109 : : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_mem_slab, alloc, slab, timeout);
110 : :
111 [ # # ]: 0 : if (slab->free_list != NULL) {
112 : : /* take a free block */
113 : 0 : *mem = slab->free_list;
114 : 0 : slab->free_list = *(char **)(slab->free_list);
115 : 0 : slab->num_used++;
116 : :
117 : : #ifdef CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION
118 : : slab->max_used = MAX(slab->num_used, slab->max_used);
119 : : #endif
120 : :
121 : 0 : result = 0;
122 [ # # ]: 0 : } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT) ||
123 : : !IS_ENABLED(CONFIG_MULTITHREADING)) {
124 : : /* don't wait for a free block to become available */
125 : 0 : *mem = NULL;
126 : 0 : result = -ENOMEM;
127 : : } else {
128 : : SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_mem_slab, alloc, slab, timeout);
129 : :
130 : : /* wait for a free block or timeout */
131 : 0 : result = z_pend_curr(&slab->lock, key, &slab->wait_q, timeout);
132 [ # # ]: 0 : if (result == 0) {
133 : 0 : *mem = _current->base.swap_data;
134 : : }
135 : :
136 : : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_mem_slab, alloc, slab, timeout, result);
137 : :
138 : 0 : return result;
139 : : }
140 : :
141 : : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_mem_slab, alloc, slab, timeout, result);
142 : :
143 : 0 : k_spin_unlock(&slab->lock, key);
144 : :
145 : 0 : return result;
146 : : }
147 : :
148 : 0 : void k_mem_slab_free(struct k_mem_slab *slab, void **mem)
149 : : {
150 : 0 : k_spinlock_key_t key = k_spin_lock(&slab->lock);
151 : :
152 : : SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_mem_slab, free, slab);
153 [ # # ]: 0 : if (slab->free_list == NULL && IS_ENABLED(CONFIG_MULTITHREADING)) {
154 : 0 : struct k_thread *pending_thread = z_unpend_first_thread(&slab->wait_q);
155 : :
156 [ # # ]: 0 : if (pending_thread != NULL) {
157 : : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_mem_slab, free, slab);
158 : :
159 : 0 : z_thread_return_value_set_with_data(pending_thread, 0, *mem);
160 : 0 : z_ready_thread(pending_thread);
161 : 0 : z_reschedule(&slab->lock, key);
162 : 0 : return;
163 : : }
164 : : }
165 : 0 : **(char ***) mem = slab->free_list;
166 : 0 : slab->free_list = *(char **) mem;
167 : 0 : slab->num_used--;
168 : :
169 : : SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_mem_slab, free, slab);
170 : :
171 : 0 : k_spin_unlock(&slab->lock, key);
172 : : }
|