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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt