• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/udebug.c

  1 /*
  2  * udebug - debug ring buffer library
  3  *
  4  * Copyright (C) 2023 Felix Fietkau <nbd@nbd.name>
  5  *
  6  * Permission to use, copy, modify, and/or distribute this software for any
  7  * purpose with or without fee is hereby granted, provided that the above
  8  * copyright notice and this permission notice appear in all copies.
  9  *
 10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17  */
 18 #define _GNU_SOURCE
 19 #include <sys/types.h>
 20 #include <sys/mman.h>
 21 #include <sys/socket.h>
 22 #include <sys/stat.h>
 23 #include <unistd.h>
 24 #include <string.h>
 25 #include <stdio.h>
 26 #include <fcntl.h>
 27 #include <errno.h>
 28 #include <poll.h>
 29 #include <time.h>
 30 #include "udebug-priv.h"
 31 #include "usock.h"
 32 
 33 #define ALIGN(i, sz)    (((i) + (sz) - 1) & ~((sz) - 1))
 34 
 35 #ifndef MAP_ANONYMOUS
 36 #define MAP_ANONYMOUS MAP_ANON
 37 #endif
 38 
 39 #define UDEBUG_MIN_ALLOC_LEN    128
 40 static struct blob_buf b;
 41 static unsigned int page_size;
 42 
 43 static void __randname(char *template)
 44 {
 45         int i;
 46         struct timespec ts;
 47         unsigned long r;
 48 
 49         clock_gettime(CLOCK_REALTIME, &ts);
 50         r = ts.tv_sec + ts.tv_nsec;
 51         for (i=0; i<6; i++, r>>=5)
 52                 template[i] = 'A'+(r&15)+(r&16)*2;
 53 }
 54 
 55 int udebug_id_cmp(const void *k1, const void *k2, void *ptr)
 56 {
 57         uint32_t id1 = (uint32_t)(uintptr_t)k1, id2 = (uint32_t)(uintptr_t)k2;
 58         if (id1 < id2)
 59                 return -1;
 60         else if (id1 > id2)
 61                 return 1;
 62         return 0;
 63 }
 64 
 65 static inline int
 66 shm_open_anon(char *name)
 67 {
 68         char *template = name + strlen(name) - 6;
 69         int fd;
 70 
 71         if (template < name || memcmp(template, "XXXXXX", 6) != 0)
 72                 return -1;
 73 
 74         for (int i = 0; i < 100; i++) {
 75                 __randname(template);
 76                 fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
 77                 if (fd >= 0) {
 78                         if (shm_unlink(name) < 0) {
 79                                 close(fd);
 80                                 continue;
 81                         }
 82                         return fd;
 83                 }
 84 
 85                 if (fd < 0 && errno != EEXIST)
 86                         return -1;
 87         }
 88 
 89         return -1;
 90 }
 91 
 92 static void __udebug_disconnect(struct udebug *ctx, bool reconnect)
 93 {
 94         uloop_fd_delete(&ctx->fd);
 95         close(ctx->fd.fd);
 96         ctx->fd.fd = -1;
 97         ctx->poll_handle = -1;
 98         if (ctx->reconnect.cb && reconnect)
 99                 uloop_timeout_set(&ctx->reconnect, 1);
100 }
101 
102 uint64_t udebug_timestamp(void)
103 {
104         struct timespec ts;
105         uint64_t val;
106 
107         clock_gettime(CLOCK_REALTIME, &ts);
108 
109         val = ts.tv_sec;
110         val *= UDEBUG_TS_SEC;
111         val += ts.tv_nsec / 1000;
112 
113         return val;
114 }
115 
116 static int
117 __udebug_buf_map(struct udebug_buf *buf, int fd)
118 {
119         unsigned int pad = 0;
120         void *ptr, *ptr2;
121         struct stat st;
122 
123         if (fstat(fd, &st) < 0 ||
124             (uint64_t)st.st_size < (uint64_t)buf->head_size + buf->data_size)
125                 return -1;
126 
127 #ifdef mips
128         pad = page_size;
129 #endif
130         ptr = mmap(NULL, buf->head_size + 2 * buf->data_size + pad, PROT_NONE,
131                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
132         if (ptr == MAP_FAILED)
133                 return -1;
134 
135 #ifdef mips
136         ptr = (void *)ALIGN((unsigned long)ptr, page_size);
137 #endif
138 
139         ptr2 = mmap(ptr, buf->head_size + buf->data_size,
140                     PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0);
141         if (ptr2 != ptr)
142                 goto err_unmap;
143 
144         ptr2 = mmap(ptr + buf->head_size + buf->data_size, buf->data_size,
145                     PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd,
146                     buf->head_size);
147         if (ptr2 != ptr + buf->head_size + buf->data_size)
148                 goto err_unmap;
149 
150         buf->hdr = ptr;
151         buf->data = ptr + buf->head_size;
152         return 0;
153 
154 err_unmap:
155         munmap(ptr, buf->head_size + 2 * buf->data_size);
156         return -1;
157 }
158 
159 static int
160 writev_retry(int fd, struct iovec *iov, int iov_len, int sock_fd)
161 {
162         uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
163         struct msghdr msghdr = { 0 };
164         struct cmsghdr *cmsg;
165         int len = 0;
166         int *pfd;
167 
168         msghdr.msg_iov = iov,
169         msghdr.msg_iovlen = iov_len,
170         msghdr.msg_control = fd_buf;
171         msghdr.msg_controllen = sizeof(fd_buf);
172 
173         cmsg = CMSG_FIRSTHDR(&msghdr);
174         cmsg->cmsg_type = SCM_RIGHTS;
175         cmsg->cmsg_level = SOL_SOCKET;
176         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
177 
178         pfd = (int *) CMSG_DATA(cmsg);
179         msghdr.msg_controllen = cmsg->cmsg_len;
180 
181         do {
182                 ssize_t cur_len;
183 
184                 if (sock_fd < 0) {
185                         msghdr.msg_control = NULL;
186                         msghdr.msg_controllen = 0;
187                 } else {
188                         *pfd = sock_fd;
189                 }
190 
191                 cur_len = sendmsg(fd, &msghdr, 0);
192                 if (cur_len < 0) {
193                         struct pollfd pfd = {
194                                 .fd = fd,
195                                 .events = POLLOUT
196                         };
197 
198                         switch(errno) {
199                         case EAGAIN:
200                                 poll(&pfd, 1, -1);
201                                 break;
202                         case EINTR:
203                                 break;
204                         default:
205                                 return -1;
206                         }
207                         continue;
208                 }
209 
210                 if (len > 0)
211                         sock_fd = -1;
212 
213                 len += cur_len;
214                 while (cur_len >= (ssize_t) iov->iov_len) {
215                         cur_len -= iov->iov_len;
216                         iov_len--;
217                         iov++;
218                         if (!iov_len)
219                                 return len;
220                 }
221                 iov->iov_base += cur_len;
222                 iov->iov_len -= cur_len;
223                 msghdr.msg_iov = iov;
224                 msghdr.msg_iovlen = iov_len;
225         } while (1);
226 
227         /* Should never reach here */
228         return -1;
229 }
230 
231 static int
232 recv_retry(int fd, struct iovec *iov, bool wait, int *recv_fd)
233 {
234         uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
235         struct msghdr msghdr = { 0 };
236         struct cmsghdr *cmsg;
237         int total = 0;
238         int bytes;
239         int *pfd;
240 
241         msghdr.msg_iov = iov,
242         msghdr.msg_iovlen = 1,
243         msghdr.msg_control = fd_buf;
244         msghdr.msg_controllen = sizeof(fd_buf);
245 
246         cmsg = CMSG_FIRSTHDR(&msghdr);
247         cmsg->cmsg_type = SCM_RIGHTS;
248         cmsg->cmsg_level = SOL_SOCKET;
249         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
250 
251         pfd = (int *) CMSG_DATA(cmsg);
252 
253         while (iov->iov_len > 0) {
254                 if (recv_fd) {
255                         msghdr.msg_control = fd_buf;
256                         msghdr.msg_controllen = cmsg->cmsg_len;
257                 } else {
258                         msghdr.msg_control = NULL;
259                         msghdr.msg_controllen = 0;
260                 }
261 
262                 *pfd = -1;
263                 bytes = recvmsg(fd, &msghdr, 0);
264                 if (!bytes)
265                         return -2;
266                 if (bytes < 0) {
267                         bytes = 0;
268                         if (errno == EINTR)
269                                 continue;
270 
271                         if (errno != EAGAIN)
272                                 return -2;
273                 }
274                 if (!wait && !bytes)
275                         return 0;
276 
277                 if (recv_fd)
278                         *recv_fd = *pfd;
279                 else if (*pfd >= 0)
280                         close(*pfd);
281 
282                 if (bytes > 0)
283                         recv_fd = NULL;
284 
285                 wait = true;
286                 iov->iov_len -= bytes;
287                 iov->iov_base += bytes;
288                 total += bytes;
289 
290                 if (iov->iov_len > 0) {
291                         struct pollfd pfd = {
292                                 .fd = fd,
293                                 .events = POLLIN
294                         };
295                         int ret;
296                         do {
297                                 ret = poll(&pfd, 1, UDEBUG_TIMEOUT);
298                         } while (ret < 0 && errno == EINTR);
299 
300                         if (!(pfd.revents & POLLIN))
301                                 return -1;
302                 }
303         }
304 
305         return total;
306 }
307 
308 static void
309 udebug_send_msg(struct udebug *ctx, struct udebug_client_msg *msg,
310                 struct blob_attr *meta, int fd)
311 {
312         struct iovec iov[2] = {
313                 { .iov_base = msg, .iov_len = sizeof(*msg) },
314                 {}
315         };
316 
317         if (!meta) {
318                 blob_buf_init(&b, 0);
319                 meta = b.head;
320         }
321 
322         iov[1].iov_base = meta;
323         iov[1].iov_len = blob_pad_len(meta);
324         writev_retry(ctx->fd.fd, iov, ARRAY_SIZE(iov), fd);
325 }
326 
327 static bool
328 udebug_recv_msg(struct udebug *ctx, struct udebug_client_msg *msg, int *fd,
329                 bool wait)
330 {
331         struct iovec iov = {
332                 .iov_base = msg,
333                 .iov_len = sizeof(*msg)
334         };
335         int ret;
336 
337         ret = recv_retry(ctx->fd.fd, &iov, wait, fd);
338         if (ret == -2)
339                 __udebug_disconnect(ctx, true);
340 
341         return ret == sizeof(*msg);
342 }
343 
344 static struct udebug_client_msg *
345 __udebug_poll(struct udebug *ctx, int *fd, bool wait)
346 {
347         static struct udebug_client_msg msg = {};
348 
349         while (udebug_recv_msg(ctx, &msg, fd, wait)) {
350                 struct udebug_remote_buf *rb;
351                 void *key;
352 
353                 if (msg.type != CL_MSG_RING_NOTIFY)
354                         return &msg;
355 
356                 if (fd && *fd >= 0)
357                         close(*fd);
358 
359                 if (!ctx->notify_cb)
360                         continue;
361 
362                 key = (void *)(uintptr_t)msg.id;
363                 rb = avl_find_element(&ctx->remote_rings, key, rb, node);
364                 if (!rb || !rb->poll)
365                         continue;
366 
367                 if (ctx->poll_handle >= 0)
368                         __atomic_fetch_or(&rb->buf.hdr->notify,
369                                           1UL << ctx->poll_handle,
370                                           __ATOMIC_RELAXED);
371                 ctx->notify_cb(ctx, rb);
372         }
373 
374         return NULL;
375 }
376 
377 static struct udebug_client_msg *
378 udebug_wait_for_response(struct udebug *ctx, struct udebug_client_msg *msg, int *rfd)
379 {
380         int type = msg->type;
381         int fd = -1;
382 
383         do {
384                 if (fd >= 0)
385                         close(fd);
386                 fd = -1;
387                 msg = __udebug_poll(ctx, &fd, true);
388         } while (msg && msg->type != type);
389         if (!msg)
390                 return NULL;
391 
392         if (rfd)
393                 *rfd = fd;
394         else if (fd >= 0)
395                 close(fd);
396 
397         return msg;
398 }
399 
400 static void
401 udebug_buf_msg(struct udebug_buf *buf, enum udebug_client_msg_type type)
402 {
403         struct udebug_client_msg msg = {
404                 .type = type,
405                 .id = buf->id,
406         };
407 
408         udebug_send_msg(buf->ctx, &msg, NULL, -1);
409         udebug_wait_for_response(buf->ctx, &msg, NULL);
410 }
411 
412 static size_t __udebug_headsize(unsigned int ring_size)
413 {
414         ring_size *= sizeof(struct udebug_ptr);
415         return ALIGN(sizeof(struct udebug_hdr) + ring_size, page_size);
416 }
417 
418 static void udebug_init_page_size(void)
419 {
420         if (page_size)
421                 return;
422         page_size = sysconf(_SC_PAGESIZE);
423 #ifdef mips
424         /* leave extra alignment room to account for data cache aliases */
425         if (page_size < 32 * 1024)
426                 page_size = 32 * 1024;
427 #endif
428 }
429 
430 int udebug_buf_open(struct udebug_buf *buf, int fd, uint32_t ring_size, uint32_t data_size)
431 {
432         udebug_init_page_size();
433         INIT_LIST_HEAD(&buf->list);
434         buf->ring_size = ring_size;
435         buf->head_size = __udebug_headsize(ring_size);
436         buf->data_size = data_size;
437 
438         if (buf->ring_size > (1U << 24) || buf->data_size > (1U << 29))
439                 return -1;
440 
441         /* ring_size and data_size come from a peer and are used as power-of-two
442          * masks when indexing the ring and data area; reject anything else. */
443         if (!buf->ring_size || (buf->ring_size & (buf->ring_size - 1)) ||
444             !buf->data_size || (buf->data_size & (buf->data_size - 1)))
445                 return -1;
446 
447         if (__udebug_buf_map(buf, fd))
448                 return -1;
449 
450         if (buf->ring_size != buf->hdr->ring_size ||
451                 buf->data_size != buf->hdr->data_size) {
452                 munmap(buf->hdr, buf->head_size + 2 * buf->data_size);
453                 buf->hdr = NULL;
454                 return -1;
455         }
456 
457         buf->fd = fd;
458 
459         return 0;
460 }
461 
462 int udebug_buf_init(struct udebug_buf *buf, size_t entries, size_t size)
463 {
464         char filename[] = "/udebug.XXXXXX";
465         unsigned int order = 12;
466         uint8_t ring_order = 5;
467         size_t head_size;
468         int fd;
469 
470         udebug_init_page_size();
471         INIT_LIST_HEAD(&buf->list);
472         if (size < page_size)
473                 size = page_size;
474         while(size > 1U << order)
475                 order++;
476         size = 1 << order;
477         while (entries > 1U << ring_order)
478                 ring_order++;
479         entries = 1 << ring_order;
480 
481         if (size > (1U << 29) || entries > (1U << 24))
482                 return -1;
483 
484         head_size = __udebug_headsize(entries);
485         while (ALIGN(sizeof(*buf->hdr) + (entries * 2) * sizeof(struct udebug_ptr), page_size) == head_size)
486                 entries *= 2;
487 
488         fd = shm_open_anon(filename);
489         if (fd < 0)
490                 return -1;
491 
492         if (ftruncate(fd, head_size + size) < 0)
493                 goto err_close;
494 
495         buf->head_size = head_size;
496         buf->data_size = size;
497         buf->ring_size = entries;
498 
499         if (__udebug_buf_map(buf, fd))
500                 goto err_close;
501 
502         buf->fd = fd;
503         buf->hdr->ring_size = entries;
504         buf->hdr->data_size = size;
505 
506         /* ensure hdr changes are visible */
507         __sync_synchronize();
508 
509         return 0;
510 
511 err_close:
512         close(fd);
513         return -1;
514 }
515 
516 static void *udebug_buf_alloc(struct udebug_buf *buf, uint32_t ofs, uint32_t len)
517 {
518         struct udebug_hdr *hdr = buf->hdr;
519 
520         hdr->data_used = u32_max(hdr->data_used, ofs + len + 1);
521 
522         /* ensure that data_used update is visible before clobbering data */
523         __sync_synchronize();
524 
525         return udebug_buf_ptr(buf, ofs);
526 }
527 
528 uint64_t udebug_buf_flags(struct udebug_buf *buf)
529 {
530         struct udebug_hdr *hdr = buf->hdr;
531         uint64_t flags;
532 
533         if (!hdr)
534                 return 0;
535 
536         flags = hdr->flags[0];
537         if (sizeof(flags) != sizeof(uintptr_t))
538                 flags |= ((uint64_t)hdr->flags[1]) << 32;
539 
540         return flags;
541 }
542 
543 void udebug_entry_init_ts(struct udebug_buf *buf, uint64_t timestamp)
544 {
545         struct udebug_hdr *hdr = buf->hdr;
546         struct udebug_ptr *ptr;
547 
548         if (!hdr)
549                 return;
550 
551         ptr = udebug_ring_ptr(hdr, hdr->head);
552         ptr->start = hdr->data_head;
553         ptr->len = 0;
554         ptr->timestamp = timestamp;
555 }
556 
557 void *udebug_entry_append(struct udebug_buf *buf, const void *data, uint32_t len)
558 {
559         struct udebug_hdr *hdr = buf->hdr;
560         struct udebug_ptr *ptr;
561         uint32_t ofs;
562         void *ret;
563 
564         if (!hdr)
565                 return NULL;
566 
567         ptr = udebug_ring_ptr(hdr, hdr->head);
568         ofs = ptr->start + ptr->len;
569         if (ptr->len + len > buf->data_size / 2)
570                 return NULL;
571 
572         ret = udebug_buf_alloc(buf, ofs, len);
573         if (data)
574                 memcpy(ret, data, len);
575         ptr->len += len;
576 
577         return ret;
578 }
579 
580 uint16_t udebug_entry_trim(struct udebug_buf *buf, uint16_t len)
581 {
582         struct udebug_hdr *hdr = buf->hdr;
583         struct udebug_ptr *ptr;
584 
585         if (!hdr)
586                 return 0;
587 
588         ptr = udebug_ring_ptr(hdr, hdr->head);
589         if (len)
590                 ptr->len -= len;
591 
592         return ptr->len;
593 }
594 
595 void udebug_entry_set_length(struct udebug_buf *buf, uint16_t len)
596 {
597         struct udebug_hdr *hdr = buf->hdr;
598         struct udebug_ptr *ptr;
599 
600         if (!hdr)
601                 return;
602 
603         ptr = udebug_ring_ptr(hdr, hdr->head);
604         ptr->len = len;
605 }
606 
607 int udebug_entry_printf(struct udebug_buf *buf, const char *fmt, ...)
608 {
609         va_list ap;
610         int ret;
611 
612         va_start(ap, fmt);
613         ret = udebug_entry_vprintf(buf, fmt, ap);
614         va_end(ap);
615 
616         return ret;
617 }
618 
619 int udebug_entry_vprintf(struct udebug_buf *buf, const char *fmt, va_list ap)
620 {
621         struct udebug_hdr *hdr = buf->hdr;
622         struct udebug_ptr *ptr;
623         uint32_t ofs;
624         uint32_t len;
625         va_list ap2;
626         char *str;
627 
628         if (!hdr)
629                 return -1;
630 
631         ptr = udebug_ring_ptr(hdr, hdr->head);
632         ofs = ptr->start + ptr->len;
633         if (ptr->len > buf->data_size / 2)
634                 return -1;
635 
636         str = udebug_buf_alloc(buf, ofs, UDEBUG_MIN_ALLOC_LEN);
637         va_copy(ap2, ap);
638         len = vsnprintf(str, UDEBUG_MIN_ALLOC_LEN, fmt, ap2);
639         va_end(ap2);
640         if (len < UDEBUG_MIN_ALLOC_LEN)
641                 goto out;
642 
643         if (ptr->len + len > buf->data_size / 2)
644                 return -1;
645 
646         udebug_buf_alloc(buf, ofs, len + 1);
647         len = vsnprintf(str, len + 1, fmt, ap);
648 
649 out:
650         ptr->len += len;
651         return 0;
652 }
653 
654 void udebug_entry_add(struct udebug_buf *buf)
655 {
656         struct udebug_hdr *hdr = buf->hdr;
657         struct udebug_ptr *ptr;
658         uint32_t notify;
659         uint8_t *data;
660 
661         if (!hdr)
662                 return;
663 
664         ptr = udebug_ring_ptr(hdr, hdr->head);
665 
666         /* ensure strings are always 0-terminated */
667         data = udebug_buf_ptr(buf, ptr->start + ptr->len);
668         *data = 0;
669         hdr->data_head = ptr->start + ptr->len + 1;
670 
671         /* ensure that all data changes are visible before advancing head */
672         __sync_synchronize();
673 
674         u32_set(&hdr->head, u32_get(&hdr->head) + 1);
675         if (!u32_get(&hdr->head))
676                 u32_set(&hdr->head_hi, u32_get(&hdr->head_hi) + 1);
677 
678         /* ensure that head change is visible */
679         __sync_synchronize();
680 
681         notify = __atomic_exchange_n(&hdr->notify, 0, __ATOMIC_RELAXED);
682         if (notify) {
683                 struct udebug_client_msg msg = {
684                         .type = CL_MSG_RING_NOTIFY,
685                         .id = buf->id,
686                         .notify_mask = notify,
687                 };
688                 blob_buf_init(&b, 0);
689 
690                 udebug_send_msg(buf->ctx, &msg, b.head, -1);
691         }
692 }
693 void udebug_buf_free(struct udebug_buf *buf)
694 {
695         struct udebug *ctx = buf->ctx;
696 
697         if (!list_empty(&buf->list) && buf->list.prev)
698                 list_del(&buf->list);
699 
700         if (ctx && ctx->fd.fd >= 0)
701                 udebug_buf_msg(buf, CL_MSG_RING_REMOVE);
702 
703         munmap(buf->hdr, buf->head_size + 2 * buf->data_size);
704         close(buf->fd);
705         memset(buf, 0, sizeof(*buf));
706 }
707 
708 static void
709 __udebug_buf_add(struct udebug *ctx, struct udebug_buf *buf)
710 {
711         struct udebug_client_msg msg = {
712                 .type = CL_MSG_RING_ADD,
713                 .id = buf->id,
714                 .ring_size = buf->hdr->ring_size,
715                 .data_size = buf->hdr->data_size,
716         };
717         const struct udebug_buf_meta *meta = buf->meta;
718         void *c;
719 
720         blob_buf_init(&b, 0);
721         blobmsg_add_string(&b, "name", meta->name);
722         c = blobmsg_open_array(&b, "flags");
723         for (size_t i = 0; i < meta->n_flags; i++) {
724                 const struct udebug_buf_flag *flag = &meta->flags[i];
725                 void *e = blobmsg_open_array(&b, NULL);
726                 blobmsg_add_string(&b, NULL, flag->name);
727                 blobmsg_add_u64(&b, NULL, flag->mask);
728                 blobmsg_close_array(&b, e);
729         }
730         blobmsg_close_array(&b, c);
731 
732         udebug_send_msg(ctx, &msg, b.head, buf->fd);
733         udebug_wait_for_response(ctx, &msg, NULL);
734 }
735 
736 int udebug_buf_add(struct udebug *ctx, struct udebug_buf *buf,
737                    const struct udebug_buf_meta *meta)
738 {
739         if (!buf->hdr)
740                 return -1;
741 
742         list_add_tail(&buf->list, &ctx->local_rings);
743         buf->ctx = ctx;
744         buf->meta = meta;
745         buf->id = ctx->next_id++;
746         buf->hdr->format = meta->format;
747         buf->hdr->sub_format = meta->sub_format;
748 
749         if (ctx->fd.fd >= 0)
750                 __udebug_buf_add(ctx, buf);
751 
752         return 0;
753 }
754 
755 void udebug_init(struct udebug *ctx)
756 {
757         INIT_LIST_HEAD(&ctx->local_rings);
758         avl_init(&ctx->remote_rings, udebug_id_cmp, true, NULL);
759         ctx->fd.fd = -1;
760         ctx->poll_handle = -1;
761 }
762 
763 static void udebug_reconnect_cb(struct uloop_timeout *t)
764 {
765         struct udebug *ctx = container_of(t, struct udebug, reconnect);
766 
767         if (udebug_connect(ctx, ctx->socket_path) < 0) {
768                 uloop_timeout_set(&ctx->reconnect, 1000);
769                 return;
770         }
771 
772         udebug_add_uloop(ctx);
773 }
774 
775 void udebug_auto_connect(struct udebug *ctx, const char *path)
776 {
777         free(ctx->socket_path);
778         ctx->reconnect.cb = udebug_reconnect_cb;
779         ctx->socket_path = path ? strdup(path) : NULL;
780         if (ctx->fd.fd >= 0)
781                 return;
782 
783         udebug_reconnect_cb(&ctx->reconnect);
784 }
785 
786 int udebug_connect(struct udebug *ctx, const char *path)
787 {
788         struct udebug_remote_buf *rb;
789         struct udebug_buf *buf;
790 
791         if (ctx->fd.fd >= 0)
792                 close(ctx->fd.fd);
793         ctx->fd.fd = -1;
794 
795         if (!path)
796                 path = UDEBUG_SOCK_NAME;
797 
798         ctx->fd.fd = usock(USOCK_UNIX, path, NULL);
799         if (ctx->fd.fd < 0)
800                 return -1;
801 
802         list_for_each_entry(buf, &ctx->local_rings, list)
803                 __udebug_buf_add(ctx, buf);
804 
805         avl_for_each_element(&ctx->remote_rings, rb, node) {
806                 if (!rb->poll)
807                         continue;
808 
809                 rb->poll = false;
810                 udebug_remote_buf_set_poll(ctx, rb, true);
811         }
812 
813         return 0;
814 }
815 
816 void udebug_poll(struct udebug *ctx)
817 {
818         while (__udebug_poll(ctx, NULL, false));
819 }
820 
821 struct udebug_client_msg *
822 udebug_send_and_wait(struct udebug *ctx, struct udebug_client_msg *msg, int *rfd)
823 {
824         udebug_send_msg(ctx, msg, NULL, -1);
825 
826         return udebug_wait_for_response(ctx, msg, rfd);
827 }
828 
829 static void udebug_fd_cb(struct uloop_fd *fd, unsigned int events)
830 {
831         struct udebug *ctx = container_of(fd, struct udebug, fd);
832 
833         if (fd->eof)
834                 __udebug_disconnect(ctx, true);
835 
836         udebug_poll(ctx);
837 }
838 
839 void udebug_add_uloop(struct udebug *ctx)
840 {
841         if (ctx->fd.registered)
842                 return;
843 
844         ctx->fd.cb = udebug_fd_cb;
845         uloop_fd_add(&ctx->fd, ULOOP_READ);
846 }
847 
848 void udebug_free(struct udebug *ctx)
849 {
850         struct udebug_remote_buf *rb, *tmp;
851         struct udebug_buf *buf;
852 
853         free(ctx->socket_path);
854         ctx->socket_path = NULL;
855 
856         __udebug_disconnect(ctx, false);
857         uloop_timeout_cancel(&ctx->reconnect);
858 
859         while (!list_empty(&ctx->local_rings)) {
860                 buf = list_first_entry(&ctx->local_rings, struct udebug_buf, list);
861                 udebug_buf_free(buf);
862         }
863 
864         avl_for_each_element_safe(&ctx->remote_rings, rb, node, tmp)
865                 udebug_remote_buf_unmap(ctx, rb);
866 }
867 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt