1 /*
2 * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #if defined(__ZEPHYR__) && !(defined(CONFIG_BOARD_NATIVE_POSIX_32BIT) \
7 || defined(CONFIG_BOARD_NATIVE_POSIX_64BIT) \
8 || defined(CONFIG_SOC_SERIES_BSIM_NRFXX))
9
10 #include <net/socket.h>
11 #include <posix/pthread.h>
12 #include <sys/util.h>
13 #include <posix/unistd.h>
14
15 #else
16
17 #include <poll.h>
18 #include <pthread.h>
19 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
24
25 #endif
26
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #define NUM_SOCKETPAIRS 3
33 #define NUM_REPITITIONS 3
34
35 struct ctx {
36 int spair[2];
37 pthread_t thread;
38 char *name;
39 };
40
41 static const char *const names[] = {
42 "Alpha",
43 "Bravo",
44 "Charlie",
45 };
46
47 #if defined(__ZEPHYR__) && !(defined(CONFIG_BOARD_NATIVE_POSIX_32BIT) \
48 || defined(CONFIG_BOARD_NATIVE_POSIX_64BIT) \
49 || defined(CONFIG_SOC_SERIES_BSIM_NRFXX))
50
51 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
52 static pthread_attr_t attr[NUM_SOCKETPAIRS];
53 K_THREAD_STACK_ARRAY_DEFINE(stack, NUM_SOCKETPAIRS, STACK_SIZE);
54
55 #endif
56
hello(int fd,const char * name)57 static void hello(int fd, const char *name)
58 {
59 /* write(2) should be used after #25443 */
60 int res = send(fd, name, strlen(name), 0);
61
62 if (res != strlen(name)) {
63 printf("%s(): send: expected: %d actual: %d errno: %d\n",
64 __func__, (int)strlen(name), res, errno);
65 }
66 }
67
fun(void * arg)68 static void *fun(void *arg)
69 {
70 struct ctx *const ctx = (struct ctx *)arg;
71 int fd = ctx->spair[1];
72 const char *name = ctx->name;
73
74 for (size_t i = 0; i < NUM_REPITITIONS; ++i) {
75 hello(fd, name);
76 }
77
78 close(fd);
79 printf("%s closed fd %d\n", name, fd);
80 ctx->spair[1] = -1;
81
82 return NULL;
83 }
84
fd_to_idx(int fd,struct ctx * ctx,size_t n)85 static int fd_to_idx(int fd, struct ctx *ctx, size_t n)
86 {
87 int r = -1;
88 size_t i;
89
90 for (i = 0; i < n; ++i) {
91 if (ctx[i].spair[0] == fd) {
92 r = i;
93 break;
94 }
95 }
96
97 return r;
98 }
99
100 #ifdef __ZEPHYR__
zephyr_app_main(void)101 void zephyr_app_main(void)
102 {
103 #else
104 int main(int argc, char *argv[])
105 {
106 (void) argc;
107 (void) argv;
108 #endif
109
110 int r;
111 int fd;
112 int idx;
113 int poll_r;
114 size_t i;
115 size_t num_active;
116 char buf[32];
117 struct ctx ctx[NUM_SOCKETPAIRS] = {};
118 struct pollfd fds[NUM_SOCKETPAIRS] = {};
119 void *unused;
120 pthread_attr_t *attrp = NULL;
121
122 for (i = 0; i < ARRAY_SIZE(ctx); ++i) {
123 ctx[i].name = (char *)names[i];
124 r = socketpair(AF_UNIX, SOCK_STREAM, 0, ctx[i].spair);
125 if (r != 0) {
126 printf("socketpair failed: %d\n", errno);
127 goto out;
128 }
129
130 #if defined(__ZEPHYR__) && !(defined(CONFIG_BOARD_NATIVE_POSIX_32BIT) \
131 || defined(CONFIG_BOARD_NATIVE_POSIX_64BIT) \
132 || defined(CONFIG_SOC_SERIES_BSIM_NRFXX))
133 /* Zephyr requires a non-NULL attribute for pthread_create */
134 attrp = &attr[i];
135 r = pthread_attr_init(attrp);
136 if (r != 0) {
137 printf("pthread_attr_init() failed: %d", r);
138 goto out;
139 }
140
141 r = pthread_attr_setstack(attrp, &stack[i], STACK_SIZE);
142 if (r != 0) {
143 printf("pthread_attr_setstack() failed: %d", r);
144 goto out;
145 }
146 #endif
147
148 r = pthread_create(&ctx[i].thread, attrp, fun, &ctx[i]);
149 if (r != 0) {
150 printf("pthread_create failed: %d\n", r);
151 goto out;
152 }
153
154 printf("%s: socketpair: %d <=> %d\n",
155 ctx[i].name, ctx[i].spair[0], ctx[i].spair[1]);
156 }
157
158 /* loop until all threads are done */
159 for (;;) {
160
161 /* count threads that are still running and fill in pollfds */
162 for (i = 0, num_active = 0; i < ARRAY_SIZE(ctx); ++i) {
163 if (ctx[i].spair[0] == -1) {
164 continue;
165 }
166 fds[num_active].fd = ctx[i].spair[0];
167 fds[num_active].events = POLLIN;
168 fds[num_active].revents = 0;
169 num_active++;
170 }
171
172 if (num_active == 0) {
173 /* all threads are done */
174 break;
175 }
176
177 poll_r = poll(fds, num_active, -1);
178
179 for (size_t i = 0; i < num_active; ++i) {
180
181 fd = fds[i].fd;
182 idx = fd_to_idx(fd, ctx, ARRAY_SIZE(ctx));
183 if (idx < 0) {
184 printf("failed to map fd %d to index\n", fd);
185 continue;
186 }
187
188 if ((fds[i].revents & POLLIN) != 0) {
189
190 memset(buf, '\0', sizeof(buf));
191
192 /* read(2) should be used after #25443 */
193 r = recv(fd, buf, sizeof(buf), 0);
194 printf("fd: %d: read %d bytes\n", fd, r);
195 }
196
197 if ((fds[i].revents & POLLERR) != 0) {
198 printf("fd: %d: error\n", fd);
199 }
200
201 if ((fds[i].revents & POLLHUP) != 0) {
202 printf("fd: %d: hung up\n", fd);
203 close(ctx[idx].spair[0]);
204 printf("%s: closed fd %d\n", __func__,
205 ctx[idx].spair[0]);
206 pthread_join(ctx[idx].thread, &unused);
207 printf("joined %s\n", ctx[idx].name);
208 ctx[idx].spair[0] = -1;
209 }
210 }
211 }
212
213 printf("finished!\n");
214
215 out:
216 #ifndef __ZEPHYR__
217 return 0;
218 #else
219 return;
220 #endif
221 }
222