blob: 6dfa7b62758dfaebe12d25f66aaa858dc873a060 [file] [log] [blame]
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +02001#ifndef __XREF_H__
2#define __XREF_H__
3
Thierry FOURNIER952939d2017-09-01 14:17:32 +02004#include <common/hathreads.h>
5
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +02006/* xref is used to create relation between two elements.
7 * Once an element is released, it breaks the relation. If the
8 * relation is already broken, it frees the xref struct.
9 * The pointer between two elements is sort of a refcount with
10 * max value 1. The relation is only between two elements.
11 * The pointer and the type of elements a and b are conventional.
12 */
13
14struct xref {
15 struct xref *peer;
16};
17
Thierry FOURNIER952939d2017-09-01 14:17:32 +020018#define XREF_BUSY ((struct xref *)1)
19
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +020020static inline void xref_create(struct xref *xref_a, struct xref *xref_b)
21{
22 xref_a->peer = xref_b;
23 xref_b->peer = xref_a;
24}
25
Thierry FOURNIER952939d2017-09-01 14:17:32 +020026static inline struct xref *xref_get_peer_and_lock(struct xref *xref)
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +020027{
Thierry FOURNIER952939d2017-09-01 14:17:32 +020028 struct xref *local;
29 struct xref *remote;
30
31 while (1) {
32
33 /* Get the local pointer to the peer. */
34 local = HA_ATOMIC_XCHG(&xref->peer, XREF_BUSY);
35
36 /* If the local pointer is NULL, the peer no longer exists. */
37 if (local == NULL) {
38 xref->peer = NULL;
39 return NULL;
40 }
41
42 /* If the local pointeru is BUSY, the peer try to acquire the
43 * lock. We retry the process.
44 */
45 if (local == XREF_BUSY)
46 continue;
47
48 /* We are locked, the peer cant disapear, try to acquire
49 * the pper's lock. Note that remote can't be NULL.
50 */
51 remote = HA_ATOMIC_XCHG(&local->peer, XREF_BUSY);
52
53 /* The remote lock is BUSY, We retry the process. */
54 if (remote == XREF_BUSY) {
55 xref->peer = local;
56 continue;
57 }
58
59 /* We have the lock, we return the value of the xref. */
60 return local;
61 }
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +020062}
63
Thierry FOURNIER952939d2017-09-01 14:17:32 +020064static inline void xref_unlock(struct xref *xref, struct xref *peer)
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +020065{
Thierry FOURNIER952939d2017-09-01 14:17:32 +020066 /* Release the peer. */
67 peer->peer = xref;
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +020068
Thierry FOURNIER952939d2017-09-01 14:17:32 +020069 /* Release myself. */
70 xref->peer = peer;
71}
72
73static inline void xref_disconnect(struct xref *xref, struct xref *peer)
74{
75 peer->peer = NULL;
Thierry FOURNIER3c65b7a2017-08-31 20:35:18 +020076 xref->peer = NULL;
77}
78
79#endif /* __XREF_H__ */