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