1 
2 /*
3  * Copyright (C) Max Romanov
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_port_hash.h>
8 
9 
10 // Explicitly using 32 bit types to avoid possible alignment.
11 typedef struct {
12     int32_t   pid;
13     uint32_t  port_id;
14 } nxt_pid_port_id_t;
15 
16 
17 static nxt_int_t
nxt_port_hash_test(nxt_lvlhsh_query_t * lhq,void * data)18 nxt_port_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
19 {
20     nxt_port_t         *port;
21     nxt_pid_port_id_t  *pid_port_id;
22 
23     port = data;
24     pid_port_id = (nxt_pid_port_id_t *) lhq->key.start;
25 
26     if (lhq->key.length == sizeof(nxt_pid_port_id_t)
27         && pid_port_id->pid == port->pid
28         && pid_port_id->port_id == port->id)
29     {
30         return NXT_OK;
31     }
32 
33     return NXT_DECLINED;
34 }
35 
36 static const nxt_lvlhsh_proto_t  lvlhsh_ports_proto  nxt_aligned(64) = {
37     NXT_LVLHSH_DEFAULT,
38     nxt_port_hash_test,
39     nxt_lvlhsh_alloc,
40     nxt_lvlhsh_free,
41 };
42 
43 
44 nxt_port_t *
nxt_port_hash_retrieve(nxt_lvlhsh_t * port_hash)45 nxt_port_hash_retrieve(nxt_lvlhsh_t *port_hash)
46 {
47     return nxt_lvlhsh_retrieve(port_hash, &lvlhsh_ports_proto, NULL);
48 }
49 
50 
51 nxt_inline void
nxt_port_hash_lhq(nxt_lvlhsh_query_t * lhq,nxt_pid_port_id_t * pid_port)52 nxt_port_hash_lhq(nxt_lvlhsh_query_t *lhq, nxt_pid_port_id_t *pid_port)
53 {
54     lhq->key_hash = nxt_murmur_hash2(pid_port, sizeof(nxt_pid_port_id_t));
55     lhq->key.length = sizeof(nxt_pid_port_id_t);
56     lhq->key.start = (u_char *) pid_port;
57     lhq->proto = &lvlhsh_ports_proto;
58     lhq->pool = NULL;
59 }
60 
61 
62 nxt_int_t
nxt_port_hash_add(nxt_lvlhsh_t * port_hash,nxt_port_t * port)63 nxt_port_hash_add(nxt_lvlhsh_t *port_hash, nxt_port_t *port)
64 {
65     nxt_int_t           res;
66     nxt_pid_port_id_t   pid_port;
67     nxt_lvlhsh_query_t  lhq;
68 
69     pid_port.pid = port->pid;
70     pid_port.port_id = port->id;
71 
72     nxt_port_hash_lhq(&lhq, &pid_port);
73     lhq.replace = 0;
74     lhq.value = port;
75 
76     res = nxt_lvlhsh_insert(port_hash, &lhq);
77 
78     switch (res) {
79 
80     case NXT_OK:
81         break;
82 
83     default:
84         nxt_thread_log_error(NXT_LOG_WARN, "port #%d for pid %PI add failed",
85                              port->id, port->pid);
86         break;
87     }
88 
89     return res;
90 }
91 
92 
93 nxt_int_t
nxt_port_hash_remove(nxt_lvlhsh_t * port_hash,nxt_port_t * port)94 nxt_port_hash_remove(nxt_lvlhsh_t *port_hash, nxt_port_t *port)
95 {
96     nxt_int_t           res;
97     nxt_pid_port_id_t   pid_port;
98     nxt_lvlhsh_query_t  lhq;
99 
100     pid_port.pid = port->pid;
101     pid_port.port_id = port->id;
102 
103     nxt_port_hash_lhq(&lhq, &pid_port);
104 
105     res = nxt_lvlhsh_delete(port_hash, &lhq);
106 
107     switch (res) {
108 
109     case NXT_OK:
110         break;
111 
112     default:
113         nxt_thread_log_error(NXT_LOG_WARN, "port #%d for pid %PI remove failed",
114                              port->id, port->pid);
115         break;
116     }
117 
118     return res;
119 }
120 
121 
122 nxt_port_t *
nxt_port_hash_find(nxt_lvlhsh_t * port_hash,nxt_pid_t pid,nxt_port_id_t port_id)123 nxt_port_hash_find(nxt_lvlhsh_t *port_hash, nxt_pid_t pid,
124     nxt_port_id_t port_id)
125 {
126     nxt_pid_port_id_t   pid_port;
127     nxt_lvlhsh_query_t  lhq;
128 
129     pid_port.pid = pid;
130     pid_port.port_id = port_id;
131 
132     nxt_port_hash_lhq(&lhq, &pid_port);
133 
134     if (nxt_lvlhsh_find(port_hash, &lhq) == NXT_OK) {
135         nxt_thread_log_debug("process port (%PI, %d) found", pid, port_id);
136         return lhq.value;
137     }
138 
139     nxt_thread_log_debug("process port (%PI, %d) not found", pid, port_id);
140 
141     return NULL;
142 }
143