/src/haproxy/include/haproxy/port_range.h
Line | Count | Source |
1 | | /* |
2 | | * include/haproxy/port_range.h |
3 | | * This file defines everything needed to manage port ranges |
4 | | * |
5 | | * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation, version 2.1 |
10 | | * exclusively. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #ifndef _HAPROXY_PORT_RANGE_H |
23 | | #define _HAPROXY_PORT_RANGE_H |
24 | | |
25 | | #include <stdlib.h> |
26 | | #include <haproxy/api.h> |
27 | | #include <haproxy/port_range-t.h> |
28 | | |
29 | | #define GET_NEXT_OFF(range, off) ((off) == (range)->size - 1 ? 0 : (off) + 1) |
30 | | |
31 | | /* return an available port from range <range>, or zero if none is left */ |
32 | | static inline int port_range_alloc_port(struct port_range *range) |
33 | 0 | { |
34 | 0 | int ret; |
35 | 0 | int get; |
36 | 0 | int put; |
37 | |
|
38 | 0 | get = _HA_ATOMIC_LOAD(&range->get); |
39 | 0 | do { |
40 | | /* barrier to make sure get is loaded before put */ |
41 | 0 | __ha_barrier_atomic_load(); |
42 | 0 | put = _HA_ATOMIC_LOAD(&range->put_t); |
43 | 0 | if (unlikely(put == get)) |
44 | 0 | return 0; |
45 | 0 | ret = range->ports[get]; |
46 | 0 | } while (!(_HA_ATOMIC_CAS(&range->get, &get, GET_NEXT_OFF(range, get)))); |
47 | 0 | return ret; |
48 | 0 | } Unexecuted instantiation: fd.c:port_range_alloc_port Unexecuted instantiation: server.c:port_range_alloc_port Unexecuted instantiation: check.c:port_range_alloc_port Unexecuted instantiation: proto_tcp.c:port_range_alloc_port |
49 | | |
50 | | /* release port <port> into port range <range>. Does nothing if <port> is zero |
51 | | * nor if <range> is null. The caller is responsible for marking the port |
52 | | * unused by either setting the port to zero or the range to NULL. |
53 | | */ |
54 | | static inline void port_range_release_port(struct port_range *range, int port) |
55 | 0 | { |
56 | 0 | int put; |
57 | |
|
58 | 0 | if (!port || !range) |
59 | 0 | return; |
60 | | |
61 | 0 | put = range->put_h; |
62 | | /* put_h is reserved for producers, so that they can each get a |
63 | | * free slot, put_t is what is used by consumers to know if there's |
64 | | * elements available or not |
65 | | */ |
66 | | /* First reserve or slot, we know the ring buffer can't be full, |
67 | | * as we will only ever release port we allocated before |
68 | | */ |
69 | 0 | while (!(_HA_ATOMIC_CAS(&range->put_h, &put, GET_NEXT_OFF(range, put)))); |
70 | 0 | _HA_ATOMIC_STORE(&range->ports[put], port); |
71 | | /* Barrier to make sure the new port is visible before we change put_t */ |
72 | 0 | __ha_barrier_atomic_store(); |
73 | | /* Wait until all the threads that got a slot before us are done */ |
74 | 0 | while ((volatile int)range->put_t != put) |
75 | 0 | __ha_compiler_barrier(); |
76 | | /* Let the world know we're done, and any potential consumer they |
77 | | * can use that port. |
78 | | */ |
79 | 0 | _HA_ATOMIC_STORE(&range->put_t, GET_NEXT_OFF(range, put)); |
80 | 0 | } Unexecuted instantiation: fd.c:port_range_release_port Unexecuted instantiation: server.c:port_range_release_port Unexecuted instantiation: check.c:port_range_release_port Unexecuted instantiation: proto_tcp.c:port_range_release_port |
81 | | |
82 | | /* return a new initialized port range of N ports. The ports are not |
83 | | * filled in, it's up to the caller to do it. |
84 | | */ |
85 | | static inline struct port_range *port_range_alloc_range(int n) |
86 | 0 | { |
87 | 0 | struct port_range *ret; |
88 | 0 | ret = calloc(1, sizeof(struct port_range) + |
89 | 0 | (n + 1) * sizeof(((struct port_range *)0)->ports[0])); |
90 | 0 | if (!ret) |
91 | 0 | return NULL; |
92 | 0 | ret->size = n + 1; |
93 | | /* Start at the first free element */ |
94 | 0 | ret->put_h = ret->put_t = n; |
95 | 0 | return ret; |
96 | 0 | } Unexecuted instantiation: fd.c:port_range_alloc_range Unexecuted instantiation: server.c:port_range_alloc_range Unexecuted instantiation: check.c:port_range_alloc_range Unexecuted instantiation: proto_tcp.c:port_range_alloc_range |
97 | | |
98 | | #endif /* _HAPROXY_PORT_RANGE_H */ |
99 | | |
100 | | /* |
101 | | * Local variables: |
102 | | * c-indent-level: 8 |
103 | | * c-basic-offset: 8 |
104 | | * End: |
105 | | */ |