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