1 /*
2 * Copyright (c) 2019 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/sys/fdtable.h>
10 #include <errno.h>
11
12 /* The thread will test that the refcounting of fd object will
13 * work as expected.
14 */
15 static struct k_thread fd_thread;
16 static int shared_fd;
17
18 static struct fd_op_vtable fd_vtable = { 0 };
19
20 #define VTABLE_INIT (&fd_vtable)
21
22 K_THREAD_STACK_DEFINE(fd_thread_stack, CONFIG_ZTEST_STACK_SIZE +
23 CONFIG_TEST_EXTRA_STACK_SIZE);
24
ZTEST(fdtable,test_zvfs_reserve_fd)25 ZTEST(fdtable, test_zvfs_reserve_fd)
26 {
27 int fd = zvfs_reserve_fd(); /* function being tested */
28
29 zassert_true(fd >= 0, "fd < 0");
30
31 zvfs_free_fd(fd);
32 }
33
ZTEST(fdtable,test_zvfs_get_fd_obj_and_vtable)34 ZTEST(fdtable, test_zvfs_get_fd_obj_and_vtable)
35 {
36 const struct fd_op_vtable *vtable;
37
38 int fd = zvfs_reserve_fd();
39 zassert_true(fd >= 0, "fd < 0");
40
41 int *obj;
42 obj = zvfs_get_fd_obj_and_vtable(fd, &vtable,
43 NULL); /* function being tested */
44
45 zassert_is_null(obj, "obj is not NULL");
46
47 zvfs_free_fd(fd);
48 }
49
ZTEST(fdtable,test_zvfs_get_fd_obj)50 ZTEST(fdtable, test_zvfs_get_fd_obj)
51 {
52 int fd = zvfs_reserve_fd();
53 zassert_true(fd >= 0, "fd < 0");
54
55 int err = -1;
56 const struct fd_op_vtable *vtable = 0;
57 const struct fd_op_vtable *vtable2 = vtable+1;
58
59 int *obj = zvfs_get_fd_obj(fd, vtable, err); /* function being tested */
60
61 /* take branch -- if (_check_fd(fd) < 0) */
62 zassert_is_null(obj, "obj not is NULL");
63
64 obj = (void *)1;
65 vtable = NULL;
66
67 /* This will set obj and vtable properly */
68 zvfs_finalize_fd(fd, obj, vtable);
69
70 obj = zvfs_get_fd_obj(-1, vtable, err); /* function being tested */
71
72 zassert_equal_ptr(obj, NULL, "obj is not NULL when fd < 0");
73 zassert_equal(errno, EBADF, "fd: out of bounds error");
74
75 /* take branch -- if (vtable != NULL && fd_entry->vtable != vtable) */
76 obj = zvfs_get_fd_obj(fd, vtable2, err); /* function being tested */
77
78 zassert_equal_ptr(obj, NULL, "obj is not NULL - vtable doesn't match");
79 zassert_equal(errno, err, "vtable matches");
80
81 zvfs_free_fd(fd);
82 }
83
ZTEST(fdtable,test_zvfs_finalize_fd)84 ZTEST(fdtable, test_zvfs_finalize_fd)
85 {
86 const struct fd_op_vtable *vtable;
87
88 int fd = zvfs_reserve_fd();
89 zassert_true(fd >= 0);
90
91 int *obj = zvfs_get_fd_obj_and_vtable(fd, &vtable, NULL);
92
93 const struct fd_op_vtable *original_vtable = vtable;
94 int *original_obj = obj;
95
96 zvfs_finalize_fd(fd, obj, vtable); /* function being tested */
97
98 obj = zvfs_get_fd_obj_and_vtable(fd, &vtable, NULL);
99
100 zassert_equal_ptr(obj, original_obj, "obj is different after finalizing");
101 zassert_equal_ptr(vtable, original_vtable, "vtable is different after finalizing");
102
103 zvfs_free_fd(fd);
104 }
105
ZTEST(fdtable,test_zvfs_alloc_fd)106 ZTEST(fdtable, test_zvfs_alloc_fd)
107 {
108 const struct fd_op_vtable *vtable = NULL;
109 int *obj = NULL;
110
111 int fd = zvfs_alloc_fd(obj, vtable); /* function being tested */
112 zassert_true(fd >= 0);
113
114 obj = zvfs_get_fd_obj_and_vtable(fd, &vtable, NULL);
115
116 zassert_equal_ptr(obj, NULL, "obj is different after allocating");
117 zassert_equal_ptr(vtable, NULL, "vtable is different after allocating");
118
119 zvfs_free_fd(fd);
120 }
121
ZTEST(fdtable,test_zvfs_free_fd)122 ZTEST(fdtable, test_zvfs_free_fd)
123 {
124 const struct fd_op_vtable *vtable = NULL;
125
126 int fd = zvfs_reserve_fd();
127 zassert_true(fd >= 0);
128
129 zvfs_free_fd(fd); /* function being tested */
130
131 int *obj = zvfs_get_fd_obj_and_vtable(fd, &vtable, NULL);
132
133 zassert_equal_ptr(obj, NULL, "obj is not NULL after freeing");
134 }
135
test_cb(void * p1,void * p2,void * p3)136 static void test_cb(void *p1, void *p2, void *p3)
137 {
138 ARG_UNUSED(p2);
139 ARG_UNUSED(p3);
140
141 int fd = POINTER_TO_INT(p1);
142 const struct fd_op_vtable *vtable;
143 int *obj;
144
145 obj = zvfs_get_fd_obj_and_vtable(fd, &vtable, NULL);
146
147 zassert_not_null(obj, "obj is null");
148 zassert_not_null(vtable, "vtable is null");
149
150 zvfs_free_fd(fd);
151
152 obj = zvfs_get_fd_obj_and_vtable(fd, &vtable, NULL);
153 zassert_is_null(obj, "obj is still there");
154 zassert_equal(errno, EBADF, "fd was found");
155 }
156
ZTEST(fdtable,test_z_fd_multiple_access)157 ZTEST(fdtable, test_z_fd_multiple_access)
158 {
159 const struct fd_op_vtable *vtable = VTABLE_INIT;
160 void *obj = (void *)vtable;
161
162 shared_fd = zvfs_reserve_fd();
163 zassert_true(shared_fd >= 0, "fd < 0");
164
165 zvfs_finalize_fd(shared_fd, obj, vtable);
166
167 k_thread_create(&fd_thread, fd_thread_stack,
168 K_THREAD_STACK_SIZEOF(fd_thread_stack),
169 test_cb,
170 INT_TO_POINTER(shared_fd), NULL, NULL,
171 CONFIG_ZTEST_THREAD_PRIORITY, 0, K_NO_WAIT);
172
173 k_thread_join(&fd_thread, K_FOREVER);
174
175 /* should be null since freed in the other thread */
176 obj = zvfs_get_fd_obj_and_vtable(shared_fd, &vtable, NULL);
177 zassert_is_null(obj, "obj is still there");
178 zassert_equal(errno, EBADF, "fd was found");
179 }
180
181 ZTEST_SUITE(fdtable, NULL, NULL, NULL, NULL, NULL);
182