VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/proxy_pollmgr.c@ 68753

最後變更 在這個檔案從68753是 68753,由 vboxsync 提交於 8 年 前

Rewrite "channels". Use RTREQQUEUE to schedule requests on the
pollmgr thread and just one socket to wake up poll(2). To minimize
churn keep the old API, so no other files are affected.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 22.0 KB
 
1/* $Id: proxy_pollmgr.c 68753 2017-09-14 02:15:39Z vboxsync $ */
2/** @file
3 * NAT Network - poll manager.
4 */
5
6/*
7 * Copyright (C) 2013-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_NAT_SERVICE
19
20#include "winutils.h"
21
22#include "proxy_pollmgr.h"
23#include "proxy.h"
24
25#ifndef RT_OS_WINDOWS
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <err.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <poll.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <time.h>
36#include <unistd.h>
37#else
38#include <iprt/err.h>
39#include <stdlib.h>
40#include <string.h>
41#include "winpoll.h"
42#endif
43
44#include <iprt/req.h>
45#include <iprt/err.h>
46
47
48#define POLLMGR_GARBAGE (-1)
49
50
51enum {
52 POLLMGR_QUEUE = 0,
53
54 POLLMGR_SLOT_STATIC_COUNT,
55 POLLMGR_SLOT_FIRST_DYNAMIC = POLLMGR_SLOT_STATIC_COUNT
56};
57
58
59struct pollmgr_chan {
60 struct pollmgr_handler *handler;
61 void *arg;
62 bool arg_valid;
63};
64
65struct pollmgr {
66 struct pollfd *fds;
67 struct pollmgr_handler **handlers;
68 nfds_t capacity; /* allocated size of the arrays */
69 nfds_t nfds; /* part of the arrays in use */
70
71 /* channels (socketpair) for static slots */
72 SOCKET chan[POLLMGR_SLOT_STATIC_COUNT][2];
73#define POLLMGR_CHFD_RD 0 /* - pollmgr side */
74#define POLLMGR_CHFD_WR 1 /* - client side */
75
76
77 /* emulate channels with request queue */
78 RTREQQUEUE queue;
79 struct pollmgr_handler queue_handler;
80 struct pollmgr_chan chan_handlers[POLLMGR_CHAN_COUNT];
81} pollmgr;
82
83
84static int pollmgr_queue_callback(struct pollmgr_handler *, SOCKET, int);
85static void pollmgr_chan_call_handler(int, void *);
86
87static void pollmgr_loop(void);
88
89static void pollmgr_add_at(int, struct pollmgr_handler *, SOCKET, int);
90static void pollmgr_refptr_delete(struct pollmgr_refptr *);
91
92
93/*
94 * We cannot portably peek at the length of the incoming datagram and
95 * pre-allocate pbuf chain to recvmsg() directly to it. On Linux it's
96 * possible to recv with MSG_PEEK|MSG_TRUC, but extra syscall is
97 * probably more expensive (haven't measured) than doing an extra copy
98 * of data, since typical UDP datagrams are small enough to avoid
99 * fragmentation.
100 *
101 * We can use shared buffer here since we read from sockets
102 * sequentially in a loop over pollfd.
103 */
104u8_t pollmgr_udpbuf[64 * 1024];
105
106
107int
108pollmgr_init(void)
109{
110 struct pollfd *newfds;
111 struct pollmgr_handler **newhdls;
112 nfds_t newcap;
113 int rc, status;
114 nfds_t i;
115
116 rc = RTReqQueueCreate(&pollmgr.queue);
117 if (RT_FAILURE(rc))
118 return -1;
119
120 pollmgr.fds = NULL;
121 pollmgr.handlers = NULL;
122 pollmgr.capacity = 0;
123 pollmgr.nfds = 0;
124
125 for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
126 pollmgr.chan[i][POLLMGR_CHFD_RD] = INVALID_SOCKET;
127 pollmgr.chan[i][POLLMGR_CHFD_WR] = INVALID_SOCKET;
128 }
129
130 for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
131#ifndef RT_OS_WINDOWS
132 int j;
133
134 status = socketpair(PF_LOCAL, SOCK_DGRAM, 0, pollmgr.chan[i]);
135 if (status < 0) {
136 DPRINTF(("socketpair: %R[sockerr]\n", SOCKERRNO()));
137 goto cleanup_close;
138 }
139
140 /* now manually make them O_NONBLOCK */
141 for (j = 0; j < 2; ++j) {
142 int s = pollmgr.chan[i][j];
143 int sflags;
144
145 sflags = fcntl(s, F_GETFL, 0);
146 if (sflags < 0) {
147 DPRINTF0(("F_GETFL: %R[sockerr]\n", errno));
148 goto cleanup_close;
149 }
150
151 status = fcntl(s, F_SETFL, sflags | O_NONBLOCK);
152 if (status < 0) {
153 DPRINTF0(("O_NONBLOCK: %R[sockerr]\n", errno));
154 goto cleanup_close;
155 }
156 }
157#else
158 status = RTWinSocketPair(PF_INET, SOCK_DGRAM, 0, pollmgr.chan[i]);
159 if (RT_FAILURE(status)) {
160 goto cleanup_close;
161 }
162#endif
163 }
164
165
166 newcap = 16; /* XXX: magic */
167 LWIP_ASSERT1(newcap >= POLLMGR_SLOT_STATIC_COUNT);
168
169 newfds = (struct pollfd *)
170 malloc(newcap * sizeof(*pollmgr.fds));
171 if (newfds == NULL) {
172 DPRINTF(("%s: Failed to allocate fds array\n", __func__));
173 goto cleanup_close;
174 }
175
176 newhdls = (struct pollmgr_handler **)
177 malloc(newcap * sizeof(*pollmgr.handlers));
178 if (newhdls == NULL) {
179 DPRINTF(("%s: Failed to allocate handlers array\n", __func__));
180 free(newfds);
181 goto cleanup_close;
182 }
183
184 pollmgr.capacity = newcap;
185 pollmgr.fds = newfds;
186 pollmgr.handlers = newhdls;
187
188 pollmgr.nfds = POLLMGR_SLOT_STATIC_COUNT;
189
190 for (i = 0; i < pollmgr.capacity; ++i) {
191 pollmgr.fds[i].fd = INVALID_SOCKET;
192 pollmgr.fds[i].events = 0;
193 pollmgr.fds[i].revents = 0;
194 }
195
196 /* add request queue notification */
197 pollmgr.queue_handler.callback = pollmgr_queue_callback;
198 pollmgr.queue_handler.data = NULL;
199 pollmgr.queue_handler.slot = -1;
200
201 pollmgr_add_at(POLLMGR_QUEUE, &pollmgr.queue_handler,
202 pollmgr.chan[POLLMGR_QUEUE][POLLMGR_CHFD_RD],
203 POLLIN);
204
205 return 0;
206
207 cleanup_close:
208 for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
209 SOCKET *chan = pollmgr.chan[i];
210 if (chan[POLLMGR_CHFD_RD] != INVALID_SOCKET) {
211 closesocket(chan[POLLMGR_CHFD_RD]);
212 closesocket(chan[POLLMGR_CHFD_WR]);
213 }
214 }
215
216 return -1;
217}
218
219
220/*
221 * Add new channel. We now implement channels with request queue, so
222 * all channels get the same socket that triggers queue processing.
223 *
224 * Must be called before pollmgr loop is started, so no locking.
225 */
226SOCKET
227pollmgr_add_chan(int slot, struct pollmgr_handler *handler)
228{
229 AssertReturn(0 <= slot && slot < POLLMGR_CHAN_COUNT, INVALID_SOCKET);
230 AssertReturn(handler != NULL && handler->callback != NULL, INVALID_SOCKET);
231
232 handler->slot = slot;
233 pollmgr.chan_handlers[slot].handler = handler;
234 return pollmgr.chan[POLLMGR_QUEUE][POLLMGR_CHFD_WR];
235}
236
237
238/*
239 * This used to actually send data over the channel's socket. Now we
240 * queue a request and send single byte notification over shared
241 * POLLMGR_QUEUE socket.
242 */
243ssize_t
244pollmgr_chan_send(int slot, void *buf, size_t nbytes)
245{
246 static const char notification = 0x5a;
247
248 void *ptr;
249 SOCKET fd;
250 ssize_t nsent;
251 int rc;
252
253 AssertReturn(0 <= slot && slot < POLLMGR_CHAN_COUNT, -1);
254
255 /*
256 * XXX: Hack alert. We only ever "sent" single pointer which was
257 * simultaneously both the wakeup event for the poll and the
258 * argument for the channel handler that it read from the channel.
259 * So now we pass this pointer to the request and arrange for the
260 * handler to "read" it when it asks for it.
261 */
262 if (nbytes != sizeof(void *)) {
263 return -1;
264 }
265
266 ptr = *(void **)buf;
267
268 rc = RTReqQueueCallEx(pollmgr.queue, NULL, 0,
269 RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
270 (PFNRT)pollmgr_chan_call_handler, 2,
271 slot, ptr);
272
273 fd = pollmgr.chan[POLLMGR_QUEUE][POLLMGR_CHFD_WR];
274 nsent = send(fd, &notification, 1, 0);
275 if (nsent == SOCKET_ERROR) {
276 DPRINTF(("send on chan %d: %R[sockerr]\n", slot, SOCKERRNO()));
277 return -1;
278 }
279 else if ((size_t)nsent != 1) {
280 DPRINTF(("send on chan %d: datagram truncated to %u bytes",
281 slot, (unsigned int)nsent));
282 return -1;
283 }
284
285 /* caller thinks it's sending the pointer */
286 return sizeof(void *);
287}
288
289
290/*
291 * pollmgr_chan_send() sent us a notification, process the queue.
292 */
293static int
294pollmgr_queue_callback(struct pollmgr_handler *handler, SOCKET fd, int revents)
295{
296 ssize_t nread;
297 int sockerr;
298 int rc;
299
300 RT_NOREF(handler, revents);
301 Assert(pollmgr.queue != NIL_RTREQQUEUE);
302
303 nread = recv(fd, (char *)pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
304 sockerr = SOCKERRNO(); /* save now, may be clobbered */
305
306 if (nread == SOCKET_ERROR) {
307 DPRINTF0(("%s: recv: %R[sockerr]\n", __func__, sockerr));
308 return POLLIN;
309 }
310
311 DPRINTF2(("%s: read %zd\n", __func__, nread));
312 if (nread == 0) {
313 return POLLIN;
314 }
315
316 rc = RTReqQueueProcess(pollmgr.queue, 0);
317 if (RT_UNLIKELY(rc != VERR_TIMEOUT && RT_FAILURE_NP(rc))) {
318 DPRINTF0(("%s: RTReqQueueProcess: %Rrc\n", __func__, rc));
319 }
320
321 return POLLIN;
322}
323
324
325/*
326 * Queued requests use this function to emulate the call to the
327 * handler's callback.
328 */
329static void
330pollmgr_chan_call_handler(int slot, void *arg)
331{
332 struct pollmgr_handler *handler;
333 int nevents;
334
335 AssertReturnVoid(0 <= slot && slot < POLLMGR_CHAN_COUNT);
336
337 handler = pollmgr.chan_handlers[slot].handler;
338 AssertReturnVoid(handler != NULL && handler->callback != NULL);
339
340 /* arrange for pollmgr_chan_recv_ptr() to "receive" the arg */
341 pollmgr.chan_handlers[slot].arg = arg;
342 pollmgr.chan_handlers[slot].arg_valid = true;
343
344 nevents = handler->callback(handler, -1, POLLIN);
345 if (nevents != POLLIN) {
346 DPRINTF2(("%s: nevents=0x%x!\n", nevents));
347 }
348}
349
350
351/*
352 * "Receive" a pointer "sent" over poll manager channel.
353 */
354void *
355pollmgr_chan_recv_ptr(struct pollmgr_handler *handler, SOCKET fd, int revents)
356{
357 int slot;
358 void *ptr;
359
360 RT_NOREF(fd);
361
362 slot = handler->slot;
363 Assert(0 <= slot && slot < POLLMGR_CHAN_COUNT);
364
365 if (revents & POLLNVAL) {
366 errx(EXIT_FAILURE, "chan %d: fd invalid", (int)handler->slot);
367 /* NOTREACHED */
368 }
369
370 if (revents & (POLLERR | POLLHUP)) {
371 errx(EXIT_FAILURE, "chan %d: fd error", (int)handler->slot);
372 /* NOTREACHED */
373 }
374
375 LWIP_ASSERT1(revents & POLLIN);
376
377 if (!pollmgr.chan_handlers[slot].arg_valid) {
378 err(EXIT_FAILURE, "chan %d: recv", (int)handler->slot);
379 /* NOTREACHED */
380 }
381
382 ptr = pollmgr.chan_handlers[slot].arg;
383 pollmgr.chan_handlers[slot].arg_valid = false;
384
385 return ptr;
386}
387
388
389/*
390 * Must be called from pollmgr loop (via callbacks), so no locking.
391 */
392int
393pollmgr_add(struct pollmgr_handler *handler, SOCKET fd, int events)
394{
395 int slot;
396
397 DPRINTF2(("%s: new fd %d\n", __func__, fd));
398
399 if (pollmgr.nfds == pollmgr.capacity) {
400 struct pollfd *newfds;
401 struct pollmgr_handler **newhdls;
402 nfds_t newcap;
403 nfds_t i;
404
405 newcap = pollmgr.capacity * 2;
406
407 newfds = (struct pollfd *)
408 realloc(pollmgr.fds, newcap * sizeof(*pollmgr.fds));
409 if (newfds == NULL) {
410 DPRINTF(("%s: Failed to reallocate fds array\n", __func__));
411 handler->slot = -1;
412 return -1;
413 }
414
415 pollmgr.fds = newfds; /* don't crash/leak if realloc(handlers) fails */
416 /* but don't update capacity yet! */
417
418 newhdls = (struct pollmgr_handler **)
419 realloc(pollmgr.handlers, newcap * sizeof(*pollmgr.handlers));
420 if (newhdls == NULL) {
421 DPRINTF(("%s: Failed to reallocate handlers array\n", __func__));
422 /* if we failed to realloc here, then fds points to the
423 * new array, but we pretend we still has old capacity */
424 handler->slot = -1;
425 return -1;
426 }
427
428 pollmgr.handlers = newhdls;
429 pollmgr.capacity = newcap;
430
431 for (i = pollmgr.nfds; i < newcap; ++i) {
432 newfds[i].fd = INVALID_SOCKET;
433 newfds[i].events = 0;
434 newfds[i].revents = 0;
435 newhdls[i] = NULL;
436 }
437 }
438
439 slot = pollmgr.nfds;
440 ++pollmgr.nfds;
441
442 pollmgr_add_at(slot, handler, fd, events);
443 return slot;
444}
445
446
447static void
448pollmgr_add_at(int slot, struct pollmgr_handler *handler, SOCKET fd, int events)
449{
450 pollmgr.fds[slot].fd = fd;
451 pollmgr.fds[slot].events = events;
452 pollmgr.fds[slot].revents = 0;
453 pollmgr.handlers[slot] = handler;
454
455 handler->slot = slot;
456}
457
458
459void
460pollmgr_update_events(int slot, int events)
461{
462 LWIP_ASSERT1(slot >= POLLMGR_SLOT_FIRST_DYNAMIC);
463 LWIP_ASSERT1((nfds_t)slot < pollmgr.nfds);
464
465 pollmgr.fds[slot].events = events;
466}
467
468
469void
470pollmgr_del_slot(int slot)
471{
472 LWIP_ASSERT1(slot >= POLLMGR_SLOT_FIRST_DYNAMIC);
473
474 DPRINTF2(("%s(%d): fd %d ! DELETED\n",
475 __func__, slot, pollmgr.fds[slot].fd));
476
477 pollmgr.fds[slot].fd = INVALID_SOCKET; /* see poll loop */
478}
479
480
481void
482pollmgr_thread(void *ignored)
483{
484 LWIP_UNUSED_ARG(ignored);
485 pollmgr_loop();
486}
487
488
489static void
490pollmgr_loop(void)
491{
492 int nready;
493 SOCKET delfirst;
494 SOCKET *pdelprev;
495 int i;
496
497 for (;;) {
498#ifndef RT_OS_WINDOWS
499 nready = poll(pollmgr.fds, pollmgr.nfds, -1);
500#else
501 int rc = RTWinPoll(pollmgr.fds, pollmgr.nfds,RT_INDEFINITE_WAIT, &nready);
502 if (RT_FAILURE(rc)) {
503 err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
504 /* NOTREACHED*/
505 }
506#endif
507
508 DPRINTF2(("%s: ready %d fd%s\n",
509 __func__, nready, (nready == 1 ? "" : "s")));
510
511 if (nready < 0) {
512 if (errno == EINTR) {
513 continue;
514 }
515
516 err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
517 /* NOTREACHED*/
518 }
519 else if (nready == 0) { /* cannot happen, we wait forever (-1) */
520 continue; /* - but be defensive */
521 }
522
523
524 delfirst = INVALID_SOCKET;
525 pdelprev = &delfirst;
526
527 for (i = 0; (nfds_t)i < pollmgr.nfds && nready > 0; ++i) {
528 struct pollmgr_handler *handler;
529 SOCKET fd;
530 int revents, nevents;
531
532 fd = pollmgr.fds[i].fd;
533 revents = pollmgr.fds[i].revents;
534
535 /*
536 * Channel handlers can request deletion of dynamic slots
537 * by calling pollmgr_del_slot() that clobbers slot's fd.
538 */
539 if (fd == INVALID_SOCKET && i >= POLLMGR_SLOT_FIRST_DYNAMIC) {
540 /* adjust count if events were pending for that slot */
541 if (revents != 0) {
542 --nready;
543 }
544
545 /* pretend that slot handler requested deletion */
546 nevents = -1;
547 goto update_events;
548 }
549
550 if (revents == 0) {
551 continue; /* next fd */
552 }
553 --nready;
554
555 handler = pollmgr.handlers[i];
556
557 if (handler != NULL && handler->callback != NULL) {
558#ifdef LWIP_PROXY_DEBUG
559# if LWIP_PROXY_DEBUG /* DEBUG */
560 if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
561 if (revents == POLLIN) {
562 DPRINTF2(("%s: ch %d\n", __func__, i));
563 }
564 else {
565 DPRINTF2(("%s: ch %d @ revents 0x%x!\n",
566 __func__, i, revents));
567 }
568 }
569 else {
570 DPRINTF2(("%s: fd %d @ revents 0x%x\n",
571 __func__, fd, revents));
572 }
573# endif /* LWIP_PROXY_DEBUG / DEBUG */
574#endif
575 nevents = (*handler->callback)(handler, fd, revents);
576 }
577 else {
578 DPRINTF0(("%s: invalid handler for fd %d: ", __func__, fd));
579 if (handler == NULL) {
580 DPRINTF0(("NULL\n"));
581 }
582 else {
583 DPRINTF0(("%p (callback = NULL)\n", (void *)handler));
584 }
585 nevents = -1; /* delete it */
586 }
587
588 update_events:
589 if (nevents >= 0) {
590 if (nevents != pollmgr.fds[i].events) {
591 DPRINTF2(("%s: fd %d ! nevents 0x%x\n",
592 __func__, fd, nevents));
593 }
594 pollmgr.fds[i].events = nevents;
595 }
596 else if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
597 /* Don't garbage-collect channels. */
598 DPRINTF2(("%s: fd %d ! DELETED (channel %d)\n",
599 __func__, fd, i));
600 pollmgr.fds[i].fd = INVALID_SOCKET;
601 pollmgr.fds[i].events = 0;
602 pollmgr.fds[i].revents = 0;
603 pollmgr.handlers[i] = NULL;
604 }
605 else {
606 DPRINTF2(("%s: fd %d ! DELETED\n", __func__, fd));
607
608 /* schedule for deletion (see g/c loop for details) */
609 *pdelprev = i; /* make previous entry point to us */
610 pdelprev = &pollmgr.fds[i].fd;
611
612 pollmgr.fds[i].fd = INVALID_SOCKET; /* end of list (for now) */
613 pollmgr.fds[i].events = POLLMGR_GARBAGE;
614 pollmgr.fds[i].revents = 0;
615 pollmgr.handlers[i] = NULL;
616 }
617 } /* processing loop */
618
619
620 /*
621 * Garbage collect and compact the array.
622 *
623 * We overload pollfd::fd of garbage entries to store the
624 * index of the next garbage entry. The garbage list is
625 * co-directional with the fds array. The index of the first
626 * entry is in "delfirst", the last entry "points to"
627 * INVALID_SOCKET.
628 *
629 * See update_events code for nevents < 0 at the end of the
630 * processing loop above.
631 */
632 while (delfirst != INVALID_SOCKET) {
633 const int last = pollmgr.nfds - 1;
634
635 /*
636 * We want a live entry in the last slot to swap into the
637 * freed slot, so make sure we have one.
638 */
639 if (pollmgr.fds[last].events == POLLMGR_GARBAGE /* garbage */
640 || pollmgr.fds[last].fd == INVALID_SOCKET) /* or killed */
641 {
642 /* drop garbage entry at the end of the array */
643 --pollmgr.nfds;
644
645 if (delfirst == (SOCKET)last) {
646 /* congruent to delnext >= pollmgr.nfds test below */
647 delfirst = INVALID_SOCKET; /* done */
648 }
649 }
650 else {
651 const SOCKET delnext = pollmgr.fds[delfirst].fd;
652
653 /* copy live entry at the end to the first slot being freed */
654 pollmgr.fds[delfirst] = pollmgr.fds[last]; /* struct copy */
655 pollmgr.handlers[delfirst] = pollmgr.handlers[last];
656 pollmgr.handlers[delfirst]->slot = (int)delfirst;
657 --pollmgr.nfds;
658
659 if ((nfds_t)delnext >= pollmgr.nfds) {
660 delfirst = INVALID_SOCKET; /* done */
661 }
662 else {
663 delfirst = delnext;
664 }
665 }
666
667 pollmgr.fds[last].fd = INVALID_SOCKET;
668 pollmgr.fds[last].events = 0;
669 pollmgr.fds[last].revents = 0;
670 pollmgr.handlers[last] = NULL;
671 }
672 } /* poll loop */
673}
674
675
676/**
677 * Create strongly held refptr.
678 */
679struct pollmgr_refptr *
680pollmgr_refptr_create(struct pollmgr_handler *ptr)
681{
682 struct pollmgr_refptr *rp;
683
684 LWIP_ASSERT1(ptr != NULL);
685
686 rp = (struct pollmgr_refptr *)malloc(sizeof (*rp));
687 if (rp == NULL) {
688 return NULL;
689 }
690
691 sys_mutex_new(&rp->lock);
692 rp->ptr = ptr;
693 rp->strong = 1;
694 rp->weak = 0;
695
696 return rp;
697}
698
699
700static void
701pollmgr_refptr_delete(struct pollmgr_refptr *rp)
702{
703 if (rp == NULL) {
704 return;
705 }
706
707 LWIP_ASSERT1(rp->strong == 0);
708 LWIP_ASSERT1(rp->weak == 0);
709
710 sys_mutex_free(&rp->lock);
711 free(rp);
712}
713
714
715/**
716 * Add weak reference before "rp" is sent over a poll manager channel.
717 */
718void
719pollmgr_refptr_weak_ref(struct pollmgr_refptr *rp)
720{
721 sys_mutex_lock(&rp->lock);
722
723 LWIP_ASSERT1(rp->ptr != NULL);
724 LWIP_ASSERT1(rp->strong > 0);
725
726 ++rp->weak;
727
728 sys_mutex_unlock(&rp->lock);
729}
730
731
732/**
733 * Try to get the pointer from implicitely weak reference we've got
734 * from a channel.
735 *
736 * If we detect that the object is still strongly referenced, but no
737 * longer registered with the poll manager we abort strengthening
738 * conversion here b/c lwip thread callback is already scheduled to
739 * destruct the object.
740 */
741struct pollmgr_handler *
742pollmgr_refptr_get(struct pollmgr_refptr *rp)
743{
744 struct pollmgr_handler *handler;
745 size_t weak;
746
747 sys_mutex_lock(&rp->lock);
748
749 LWIP_ASSERT1(rp->weak > 0);
750 weak = --rp->weak;
751
752 handler = rp->ptr;
753 if (handler == NULL) {
754 LWIP_ASSERT1(rp->strong == 0);
755 sys_mutex_unlock(&rp->lock);
756 if (weak == 0) {
757 pollmgr_refptr_delete(rp);
758 }
759 return NULL;
760 }
761
762 LWIP_ASSERT1(rp->strong == 1);
763
764 /*
765 * Here we woild do:
766 *
767 * ++rp->strong;
768 *
769 * and then, after channel handler is done, we would decrement it
770 * back.
771 *
772 * Instead we check that the object is still registered with poll
773 * manager. If it is, there's no race with lwip thread trying to
774 * drop its strong reference, as lwip thread callback to destruct
775 * the object is always scheduled by its poll manager callback.
776 *
777 * Conversly, if we detect that the object is no longer registered
778 * with poll manager, we immediately abort. Since channel handler
779 * can't do anything useful anyway and would have to return
780 * immediately.
781 *
782 * Since channel handler would always find rp->strong as it had
783 * left it, just elide extra strong reference creation to avoid
784 * the whole back-and-forth.
785 */
786
787 if (handler->slot < 0) { /* no longer polling */
788 sys_mutex_unlock(&rp->lock);
789 return NULL;
790 }
791
792 sys_mutex_unlock(&rp->lock);
793 return handler;
794}
795
796
797/**
798 * Remove (the only) strong reference.
799 *
800 * If it were real strong/weak pointers, we should also call
801 * destructor for the referenced object, but
802 */
803void
804pollmgr_refptr_unref(struct pollmgr_refptr *rp)
805{
806 sys_mutex_lock(&rp->lock);
807
808 LWIP_ASSERT1(rp->strong == 1);
809 --rp->strong;
810
811 if (rp->strong > 0) {
812 sys_mutex_unlock(&rp->lock);
813 }
814 else {
815 size_t weak;
816
817 /* void *ptr = rp->ptr; */
818 rp->ptr = NULL;
819
820 /* delete ptr; // see doc comment */
821
822 weak = rp->weak;
823 sys_mutex_unlock(&rp->lock);
824 if (weak == 0) {
825 pollmgr_refptr_delete(rp);
826 }
827 }
828}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette