xref: /unit/src/nxt_port_memory.c (revision 2126:8542c8141a13)
180Smax.romanov@nginx.com 
280Smax.romanov@nginx.com /*
380Smax.romanov@nginx.com  * Copyright (C) Max Romanov
480Smax.romanov@nginx.com  * Copyright (C) NGINX, Inc.
580Smax.romanov@nginx.com  */
642Smax.romanov@nginx.com 
742Smax.romanov@nginx.com #include <nxt_main.h>
842Smax.romanov@nginx.com 
942Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE)
1042Smax.romanov@nginx.com 
1142Smax.romanov@nginx.com #include <linux/memfd.h>
1242Smax.romanov@nginx.com #include <unistd.h>
1342Smax.romanov@nginx.com #include <sys/syscall.h>
1442Smax.romanov@nginx.com 
1542Smax.romanov@nginx.com #endif
1642Smax.romanov@nginx.com 
1780Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
1842Smax.romanov@nginx.com 
19365Smax.romanov@nginx.com 
201662Smax.romanov@nginx.com static void nxt_port_broadcast_shm_ack(nxt_task_t *task, nxt_port_t *port,
211662Smax.romanov@nginx.com     void *data);
221662Smax.romanov@nginx.com 
231662Smax.romanov@nginx.com 
24364Smax.romanov@nginx.com nxt_inline void
nxt_port_mmap_handler_use(nxt_port_mmap_handler_t * mmap_handler,int i)25365Smax.romanov@nginx.com nxt_port_mmap_handler_use(nxt_port_mmap_handler_t *mmap_handler, int i)
2642Smax.romanov@nginx.com {
27613Svbart@nginx.com     int  c;
28365Smax.romanov@nginx.com 
29365Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&mmap_handler->use_count, i);
30365Smax.romanov@nginx.com 
31365Smax.romanov@nginx.com     if (i < 0 && c == -i) {
32365Smax.romanov@nginx.com         if (mmap_handler->hdr != NULL) {
33365Smax.romanov@nginx.com             nxt_mem_munmap(mmap_handler->hdr, PORT_MMAP_SIZE);
34365Smax.romanov@nginx.com             mmap_handler->hdr = NULL;
35365Smax.romanov@nginx.com         }
36365Smax.romanov@nginx.com 
371811Smax.romanov@nginx.com         if (mmap_handler->fd != -1) {
381811Smax.romanov@nginx.com             nxt_fd_close(mmap_handler->fd);
391811Smax.romanov@nginx.com         }
401811Smax.romanov@nginx.com 
41365Smax.romanov@nginx.com         nxt_free(mmap_handler);
4242Smax.romanov@nginx.com     }
4342Smax.romanov@nginx.com }
4442Smax.romanov@nginx.com 
4542Smax.romanov@nginx.com 
46364Smax.romanov@nginx.com static nxt_port_mmap_t *
nxt_port_mmap_at(nxt_port_mmaps_t * port_mmaps,uint32_t i)47364Smax.romanov@nginx.com nxt_port_mmap_at(nxt_port_mmaps_t *port_mmaps, uint32_t i)
48141Smax.romanov@nginx.com {
49364Smax.romanov@nginx.com     uint32_t  cap;
50141Smax.romanov@nginx.com 
51364Smax.romanov@nginx.com     cap = port_mmaps->cap;
52141Smax.romanov@nginx.com 
53364Smax.romanov@nginx.com     if (cap == 0) {
54364Smax.romanov@nginx.com         cap = i + 1;
55141Smax.romanov@nginx.com     }
56141Smax.romanov@nginx.com 
57364Smax.romanov@nginx.com     while (i + 1 > cap) {
58364Smax.romanov@nginx.com 
59364Smax.romanov@nginx.com         if (cap < 16) {
601008Szelenkov@nginx.com             cap = cap * 2;
61141Smax.romanov@nginx.com 
62364Smax.romanov@nginx.com         } else {
631008Szelenkov@nginx.com             cap = cap + cap / 2;
64364Smax.romanov@nginx.com         }
65364Smax.romanov@nginx.com     }
66364Smax.romanov@nginx.com 
67364Smax.romanov@nginx.com     if (cap != port_mmaps->cap) {
68141Smax.romanov@nginx.com 
69364Smax.romanov@nginx.com         port_mmaps->elts = nxt_realloc(port_mmaps->elts,
70364Smax.romanov@nginx.com                                        cap * sizeof(nxt_port_mmap_t));
71364Smax.romanov@nginx.com         if (nxt_slow_path(port_mmaps->elts == NULL)) {
72364Smax.romanov@nginx.com             return NULL;
73364Smax.romanov@nginx.com         }
74364Smax.romanov@nginx.com 
75364Smax.romanov@nginx.com         nxt_memzero(port_mmaps->elts + port_mmaps->cap,
76364Smax.romanov@nginx.com                     sizeof(nxt_port_mmap_t) * (cap - port_mmaps->cap));
77141Smax.romanov@nginx.com 
78364Smax.romanov@nginx.com         port_mmaps->cap = cap;
79364Smax.romanov@nginx.com     }
80364Smax.romanov@nginx.com 
81364Smax.romanov@nginx.com     if (i + 1 > port_mmaps->size) {
82364Smax.romanov@nginx.com         port_mmaps->size = i + 1;
83364Smax.romanov@nginx.com     }
84364Smax.romanov@nginx.com 
85364Smax.romanov@nginx.com     return port_mmaps->elts + i;
86141Smax.romanov@nginx.com }
87141Smax.romanov@nginx.com 
88141Smax.romanov@nginx.com 
89141Smax.romanov@nginx.com void
nxt_port_mmaps_destroy(nxt_port_mmaps_t * port_mmaps,nxt_bool_t free_elts)90365Smax.romanov@nginx.com nxt_port_mmaps_destroy(nxt_port_mmaps_t *port_mmaps, nxt_bool_t free_elts)
91141Smax.romanov@nginx.com {
92141Smax.romanov@nginx.com     uint32_t         i;
93141Smax.romanov@nginx.com     nxt_port_mmap_t  *port_mmap;
94141Smax.romanov@nginx.com 
95141Smax.romanov@nginx.com     if (port_mmaps == NULL) {
96141Smax.romanov@nginx.com         return;
97141Smax.romanov@nginx.com     }
98141Smax.romanov@nginx.com 
99141Smax.romanov@nginx.com     port_mmap = port_mmaps->elts;
100141Smax.romanov@nginx.com 
101364Smax.romanov@nginx.com     for (i = 0; i < port_mmaps->size; i++) {
102365Smax.romanov@nginx.com         nxt_port_mmap_handler_use(port_mmap[i].mmap_handler, -1);
103141Smax.romanov@nginx.com     }
104141Smax.romanov@nginx.com 
105364Smax.romanov@nginx.com     port_mmaps->size = 0;
106141Smax.romanov@nginx.com 
107365Smax.romanov@nginx.com     if (free_elts != 0) {
108364Smax.romanov@nginx.com         nxt_free(port_mmaps->elts);
109141Smax.romanov@nginx.com     }
110141Smax.romanov@nginx.com }
111141Smax.romanov@nginx.com 
112141Smax.romanov@nginx.com 
113195Smax.romanov@nginx.com #define nxt_port_mmap_free_junk(p, size)                                      \
114195Smax.romanov@nginx.com     memset((p), 0xA5, size)
115195Smax.romanov@nginx.com 
116195Smax.romanov@nginx.com 
11742Smax.romanov@nginx.com static void
nxt_port_mmap_buf_completion(nxt_task_t * task,void * obj,void * data)11842Smax.romanov@nginx.com nxt_port_mmap_buf_completion(nxt_task_t *task, void *obj, void *data)
11942Smax.romanov@nginx.com {
120365Smax.romanov@nginx.com     u_char                   *p;
121365Smax.romanov@nginx.com     nxt_mp_t                 *mp;
1221455Smax.romanov@nginx.com     nxt_buf_t                *b, *next;
1231321Smax.romanov@nginx.com     nxt_process_t            *process;
124365Smax.romanov@nginx.com     nxt_chunk_id_t           c;
125365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
126365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
12742Smax.romanov@nginx.com 
128122Smax.romanov@nginx.com     if (nxt_buf_ts_handle(task, obj, data)) {
129122Smax.romanov@nginx.com         return;
130122Smax.romanov@nginx.com     }
131122Smax.romanov@nginx.com 
13242Smax.romanov@nginx.com     b = obj;
13342Smax.romanov@nginx.com 
134564Svbart@nginx.com     nxt_assert(data == b->parent);
13579Smax.romanov@nginx.com 
136365Smax.romanov@nginx.com     mmap_handler = data;
1371455Smax.romanov@nginx.com 
1381455Smax.romanov@nginx.com complete_buf:
1391455Smax.romanov@nginx.com 
140365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
14142Smax.romanov@nginx.com 
142363Smax.romanov@nginx.com     if (nxt_slow_path(hdr->src_pid != nxt_pid && hdr->dst_pid != nxt_pid)) {
143363Smax.romanov@nginx.com         nxt_debug(task, "mmap buf completion: mmap for other process pair "
144363Smax.romanov@nginx.com                   "%PI->%PI", hdr->src_pid, hdr->dst_pid);
145363Smax.romanov@nginx.com 
146363Smax.romanov@nginx.com         goto release_buf;
147363Smax.romanov@nginx.com     }
148363Smax.romanov@nginx.com 
14942Smax.romanov@nginx.com     if (b->is_port_mmap_sent && b->mem.pos > b->mem.start) {
15042Smax.romanov@nginx.com         /*
15142Smax.romanov@nginx.com          * Chunks until b->mem.pos has been sent to other side,
15242Smax.romanov@nginx.com          * let's release rest (if any).
15342Smax.romanov@nginx.com          */
15442Smax.romanov@nginx.com         p = b->mem.pos - 1;
15580Smax.romanov@nginx.com         c = nxt_port_mmap_chunk_id(hdr, p) + 1;
15680Smax.romanov@nginx.com         p = nxt_port_mmap_chunk_start(hdr, c);
157141Smax.romanov@nginx.com 
15842Smax.romanov@nginx.com     } else {
15942Smax.romanov@nginx.com         p = b->mem.start;
16080Smax.romanov@nginx.com         c = nxt_port_mmap_chunk_id(hdr, p);
16142Smax.romanov@nginx.com     }
16242Smax.romanov@nginx.com 
163195Smax.romanov@nginx.com     nxt_port_mmap_free_junk(p, b->mem.end - p);
164195Smax.romanov@nginx.com 
165494Spluknet@nginx.com     nxt_debug(task, "mmap buf completion: %p [%p,%uz] (sent=%d), "
166363Smax.romanov@nginx.com               "%PI->%PI,%d,%d", b, b->mem.start, b->mem.end - b->mem.start,
167363Smax.romanov@nginx.com               b->is_port_mmap_sent, hdr->src_pid, hdr->dst_pid, hdr->id, c);
168206Smax.romanov@nginx.com 
16942Smax.romanov@nginx.com     while (p < b->mem.end) {
170423Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_free(hdr->free_map, c);
17142Smax.romanov@nginx.com 
17242Smax.romanov@nginx.com         p += PORT_MMAP_CHUNK_SIZE;
17342Smax.romanov@nginx.com         c++;
17442Smax.romanov@nginx.com     }
17542Smax.romanov@nginx.com 
1761321Smax.romanov@nginx.com     if (hdr->dst_pid == nxt_pid
1771321Smax.romanov@nginx.com         && nxt_atomic_cmp_set(&hdr->oosm, 1, 0))
1781321Smax.romanov@nginx.com     {
1791321Smax.romanov@nginx.com         process = nxt_runtime_process_find(task->thread->runtime, hdr->src_pid);
1801321Smax.romanov@nginx.com 
1811662Smax.romanov@nginx.com         nxt_process_broadcast_shm_ack(task, process);
1821321Smax.romanov@nginx.com     }
1831321Smax.romanov@nginx.com 
184363Smax.romanov@nginx.com release_buf:
185363Smax.romanov@nginx.com 
186365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, -1);
187365Smax.romanov@nginx.com 
1881455Smax.romanov@nginx.com     next = b->next;
1891455Smax.romanov@nginx.com     mp = b->data;
1901455Smax.romanov@nginx.com 
191430Sigor@sysoev.ru     nxt_mp_free(mp, b);
192430Sigor@sysoev.ru     nxt_mp_release(mp);
1931455Smax.romanov@nginx.com 
1941455Smax.romanov@nginx.com     if (next != NULL) {
1951455Smax.romanov@nginx.com         b = next;
1961455Smax.romanov@nginx.com         mmap_handler = b->parent;
1971455Smax.romanov@nginx.com 
1981455Smax.romanov@nginx.com         goto complete_buf;
1991455Smax.romanov@nginx.com     }
20042Smax.romanov@nginx.com }
20142Smax.romanov@nginx.com 
20242Smax.romanov@nginx.com 
203365Smax.romanov@nginx.com nxt_port_mmap_handler_t *
nxt_port_incoming_port_mmap(nxt_task_t * task,nxt_process_t * process,nxt_fd_t fd)20442Smax.romanov@nginx.com nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process,
20542Smax.romanov@nginx.com     nxt_fd_t fd)
20642Smax.romanov@nginx.com {
207365Smax.romanov@nginx.com     void                     *mem;
208365Smax.romanov@nginx.com     struct stat              mmap_stat;
209365Smax.romanov@nginx.com     nxt_port_mmap_t          *port_mmap;
210365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
211365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
21242Smax.romanov@nginx.com 
21342Smax.romanov@nginx.com     nxt_debug(task, "got new mmap fd #%FD from process %PI",
21442Smax.romanov@nginx.com               fd, process->pid);
21542Smax.romanov@nginx.com 
21680Smax.romanov@nginx.com     port_mmap = NULL;
21780Smax.romanov@nginx.com 
21842Smax.romanov@nginx.com     if (fstat(fd, &mmap_stat) == -1) {
21942Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "fstat(%FD) failed %E", fd, nxt_errno);
22042Smax.romanov@nginx.com 
22142Smax.romanov@nginx.com         return NULL;
22242Smax.romanov@nginx.com     }
22342Smax.romanov@nginx.com 
22480Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, mmap_stat.st_size,
22580Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
22642Smax.romanov@nginx.com 
22780Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
22842Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "mmap() failed %E", nxt_errno);
22942Smax.romanov@nginx.com 
230364Smax.romanov@nginx.com         return NULL;
23142Smax.romanov@nginx.com     }
23242Smax.romanov@nginx.com 
233364Smax.romanov@nginx.com     hdr = mem;
234364Smax.romanov@nginx.com 
235*1977Svbart@nginx.com     if (nxt_slow_path(hdr->src_pid != process->pid
236*1977Svbart@nginx.com                       || hdr->dst_pid != nxt_pid))
237*1977Svbart@nginx.com     {
238*1977Svbart@nginx.com         nxt_log(task, NXT_LOG_WARN, "unexpected pid in mmap header detected: "
239*1977Svbart@nginx.com                 "%PI != %PI or %PI != %PI", hdr->src_pid, process->pid,
240*1977Svbart@nginx.com                 hdr->dst_pid, nxt_pid);
241*1977Svbart@nginx.com 
242*1977Svbart@nginx.com         nxt_mem_munmap(mem, PORT_MMAP_SIZE);
243*1977Svbart@nginx.com 
244*1977Svbart@nginx.com         return NULL;
245*1977Svbart@nginx.com     }
246*1977Svbart@nginx.com 
247365Smax.romanov@nginx.com     mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t));
248365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
249365Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "failed to allocate mmap_handler");
250365Smax.romanov@nginx.com 
251382Smax.romanov@nginx.com         nxt_mem_munmap(mem, PORT_MMAP_SIZE);
252382Smax.romanov@nginx.com 
253365Smax.romanov@nginx.com         return NULL;
254365Smax.romanov@nginx.com     }
255365Smax.romanov@nginx.com 
256365Smax.romanov@nginx.com     mmap_handler->hdr = hdr;
2571811Smax.romanov@nginx.com     mmap_handler->fd = -1;
258365Smax.romanov@nginx.com 
259364Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
26080Smax.romanov@nginx.com 
261364Smax.romanov@nginx.com     port_mmap = nxt_port_mmap_at(&process->incoming, hdr->id);
262364Smax.romanov@nginx.com     if (nxt_slow_path(port_mmap == NULL)) {
263364Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "failed to add mmap to incoming array");
264364Smax.romanov@nginx.com 
265364Smax.romanov@nginx.com         nxt_mem_munmap(mem, PORT_MMAP_SIZE);
266364Smax.romanov@nginx.com 
267365Smax.romanov@nginx.com         nxt_free(mmap_handler);
268365Smax.romanov@nginx.com         mmap_handler = NULL;
269365Smax.romanov@nginx.com 
270364Smax.romanov@nginx.com         goto fail;
27180Smax.romanov@nginx.com     }
27280Smax.romanov@nginx.com 
273365Smax.romanov@nginx.com     port_mmap->mmap_handler = mmap_handler;
274365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
275364Smax.romanov@nginx.com 
276323Smax.romanov@nginx.com     hdr->sent_over = 0xFFFFu;
277323Smax.romanov@nginx.com 
27880Smax.romanov@nginx.com fail:
27980Smax.romanov@nginx.com 
280364Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
28190Smax.romanov@nginx.com 
282365Smax.romanov@nginx.com     return mmap_handler;
28342Smax.romanov@nginx.com }
28442Smax.romanov@nginx.com 
28542Smax.romanov@nginx.com 
286365Smax.romanov@nginx.com static nxt_port_mmap_handler_t *
nxt_port_new_port_mmap(nxt_task_t * task,nxt_port_mmaps_t * mmaps,nxt_bool_t tracking,nxt_int_t n)2871546Smax.romanov@nginx.com nxt_port_new_port_mmap(nxt_task_t *task, nxt_port_mmaps_t *mmaps,
2881546Smax.romanov@nginx.com     nxt_bool_t tracking, nxt_int_t n)
28942Smax.romanov@nginx.com {
290365Smax.romanov@nginx.com     void                     *mem;
291365Smax.romanov@nginx.com     nxt_fd_t                 fd;
292723Smax.romanov@nginx.com     nxt_int_t                i;
293423Smax.romanov@nginx.com     nxt_free_map_t           *free_map;
294365Smax.romanov@nginx.com     nxt_port_mmap_t          *port_mmap;
295365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
296365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
297365Smax.romanov@nginx.com 
298365Smax.romanov@nginx.com     mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t));
299365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
3001546Smax.romanov@nginx.com         nxt_alert(task, "failed to allocate mmap_handler");
301365Smax.romanov@nginx.com 
302365Smax.romanov@nginx.com         return NULL;
303365Smax.romanov@nginx.com     }
30442Smax.romanov@nginx.com 
3051546Smax.romanov@nginx.com     port_mmap = nxt_port_mmap_at(mmaps, mmaps->size);
30642Smax.romanov@nginx.com     if (nxt_slow_path(port_mmap == NULL)) {
3071546Smax.romanov@nginx.com         nxt_alert(task, "failed to add port mmap to mmaps array");
30842Smax.romanov@nginx.com 
309365Smax.romanov@nginx.com         nxt_free(mmap_handler);
31042Smax.romanov@nginx.com         return NULL;
31142Smax.romanov@nginx.com     }
31242Smax.romanov@nginx.com 
3131526Smax.romanov@nginx.com     fd = nxt_shm_open(task, PORT_MMAP_SIZE);
314566Spluknet@nginx.com     if (nxt_slow_path(fd == -1)) {
31542Smax.romanov@nginx.com         goto remove_fail;
31642Smax.romanov@nginx.com     }
31742Smax.romanov@nginx.com 
318277Sigor@sysoev.ru     mem = nxt_mem_mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE,
319277Sigor@sysoev.ru                        MAP_SHARED, fd, 0);
32042Smax.romanov@nginx.com 
32180Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
3221976Svbart@nginx.com         nxt_fd_close(fd);
32342Smax.romanov@nginx.com         goto remove_fail;
32442Smax.romanov@nginx.com     }
32542Smax.romanov@nginx.com 
326365Smax.romanov@nginx.com     mmap_handler->hdr = mem;
3271546Smax.romanov@nginx.com     mmap_handler->fd = fd;
328365Smax.romanov@nginx.com     port_mmap->mmap_handler = mmap_handler;
329365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
33080Smax.romanov@nginx.com 
33142Smax.romanov@nginx.com     /* Init segment header. */
332365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
33342Smax.romanov@nginx.com 
33442Smax.romanov@nginx.com     nxt_memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map));
335423Smax.romanov@nginx.com     nxt_memset(hdr->free_tracking_map, 0xFFU, sizeof(hdr->free_tracking_map));
33642Smax.romanov@nginx.com 
3371546Smax.romanov@nginx.com     hdr->id = mmaps->size - 1;
338363Smax.romanov@nginx.com     hdr->src_pid = nxt_pid;
3391546Smax.romanov@nginx.com     hdr->sent_over = 0xFFFFu;
34080Smax.romanov@nginx.com 
34180Smax.romanov@nginx.com     /* Mark first chunk as busy */
342423Smax.romanov@nginx.com     free_map = tracking ? hdr->free_tracking_map : hdr->free_map;
343423Smax.romanov@nginx.com 
344723Smax.romanov@nginx.com     for (i = 0; i < n; i++) {
345723Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_busy(free_map, i);
346723Smax.romanov@nginx.com     }
34780Smax.romanov@nginx.com 
34842Smax.romanov@nginx.com     /* Mark as busy chunk followed the last available chunk. */
349423Smax.romanov@nginx.com     nxt_port_mmap_set_chunk_busy(hdr->free_map, PORT_MMAP_CHUNK_COUNT);
350423Smax.romanov@nginx.com     nxt_port_mmap_set_chunk_busy(hdr->free_tracking_map, PORT_MMAP_CHUNK_COUNT);
35142Smax.romanov@nginx.com 
3521546Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_DEBUG, "new mmap #%D created for %PI -> ...",
3531546Smax.romanov@nginx.com             hdr->id, nxt_pid);
35442Smax.romanov@nginx.com 
355365Smax.romanov@nginx.com     return mmap_handler;
35642Smax.romanov@nginx.com 
35742Smax.romanov@nginx.com remove_fail:
35842Smax.romanov@nginx.com 
359365Smax.romanov@nginx.com     nxt_free(mmap_handler);
360365Smax.romanov@nginx.com 
3611546Smax.romanov@nginx.com     mmaps->size--;
36242Smax.romanov@nginx.com 
36342Smax.romanov@nginx.com     return NULL;
36442Smax.romanov@nginx.com }
36542Smax.romanov@nginx.com 
36642Smax.romanov@nginx.com 
3671526Smax.romanov@nginx.com nxt_int_t
nxt_shm_open(nxt_task_t * task,size_t size)3681526Smax.romanov@nginx.com nxt_shm_open(nxt_task_t *task, size_t size)
3691526Smax.romanov@nginx.com {
3701526Smax.romanov@nginx.com     nxt_fd_t  fd;
3711526Smax.romanov@nginx.com 
3721526Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE || NXT_HAVE_SHM_OPEN)
3731526Smax.romanov@nginx.com 
3741526Smax.romanov@nginx.com     u_char    *p, name[64];
3751526Smax.romanov@nginx.com 
3761526Smax.romanov@nginx.com     p = nxt_sprintf(name, name + sizeof(name), NXT_SHM_PREFIX "unit.%PI.%uxD",
3771526Smax.romanov@nginx.com                     nxt_pid, nxt_random(&task->thread->random));
3781526Smax.romanov@nginx.com     *p = '\0';
3791526Smax.romanov@nginx.com 
3801526Smax.romanov@nginx.com #endif
3811526Smax.romanov@nginx.com 
3821526Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE)
3831526Smax.romanov@nginx.com 
3841526Smax.romanov@nginx.com     fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC);
3851526Smax.romanov@nginx.com 
3861526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
3871526Smax.romanov@nginx.com         nxt_alert(task, "memfd_create(%s) failed %E", name, nxt_errno);
3881526Smax.romanov@nginx.com 
3891526Smax.romanov@nginx.com         return -1;
3901526Smax.romanov@nginx.com     }
3911526Smax.romanov@nginx.com 
3921526Smax.romanov@nginx.com     nxt_debug(task, "memfd_create(%s): %FD", name, fd);
3931526Smax.romanov@nginx.com 
3941526Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN_ANON)
3951526Smax.romanov@nginx.com 
3961526Smax.romanov@nginx.com     fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR);
3971526Smax.romanov@nginx.com 
3981526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
3991526Smax.romanov@nginx.com         nxt_alert(task, "shm_open(SHM_ANON) failed %E", nxt_errno);
4001526Smax.romanov@nginx.com 
4011526Smax.romanov@nginx.com         return -1;
4021526Smax.romanov@nginx.com     }
4031526Smax.romanov@nginx.com 
4041526Smax.romanov@nginx.com     nxt_debug(task, "shm_open(SHM_ANON): %FD", fd);
4051526Smax.romanov@nginx.com 
4061526Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN)
4071526Smax.romanov@nginx.com 
4081526Smax.romanov@nginx.com     /* Just in case. */
4091526Smax.romanov@nginx.com     shm_unlink((char *) name);
4101526Smax.romanov@nginx.com 
4111526Smax.romanov@nginx.com     fd = shm_open((char *) name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
4121526Smax.romanov@nginx.com 
4131526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
4141526Smax.romanov@nginx.com         nxt_alert(task, "shm_open(%s) failed %E", name, nxt_errno);
4151526Smax.romanov@nginx.com 
4161526Smax.romanov@nginx.com         return -1;
4171526Smax.romanov@nginx.com     }
4181526Smax.romanov@nginx.com 
4191526Smax.romanov@nginx.com     nxt_debug(task, "shm_open(%s): %FD", name, fd);
4201526Smax.romanov@nginx.com 
4211526Smax.romanov@nginx.com     if (nxt_slow_path(shm_unlink((char *) name) == -1)) {
4221526Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "shm_unlink(%s) failed %E", name,
4231526Smax.romanov@nginx.com                 nxt_errno);
4241526Smax.romanov@nginx.com     }
4251526Smax.romanov@nginx.com 
4261526Smax.romanov@nginx.com #else
4271526Smax.romanov@nginx.com 
4281526Smax.romanov@nginx.com #error No working shared memory implementation.
4291526Smax.romanov@nginx.com 
4301526Smax.romanov@nginx.com #endif
4311526Smax.romanov@nginx.com 
4321526Smax.romanov@nginx.com     if (nxt_slow_path(ftruncate(fd, size) == -1)) {
4331526Smax.romanov@nginx.com         nxt_alert(task, "ftruncate() failed %E", nxt_errno);
4341526Smax.romanov@nginx.com 
4351526Smax.romanov@nginx.com         nxt_fd_close(fd);
4361526Smax.romanov@nginx.com 
4371526Smax.romanov@nginx.com         return -1;
4381526Smax.romanov@nginx.com     }
4391526Smax.romanov@nginx.com 
4401526Smax.romanov@nginx.com     return fd;
4411526Smax.romanov@nginx.com }
4421526Smax.romanov@nginx.com 
4431526Smax.romanov@nginx.com 
444365Smax.romanov@nginx.com static nxt_port_mmap_handler_t *
nxt_port_mmap_get(nxt_task_t * task,nxt_port_mmaps_t * mmaps,nxt_chunk_id_t * c,nxt_int_t n,nxt_bool_t tracking)4451546Smax.romanov@nginx.com nxt_port_mmap_get(nxt_task_t *task, nxt_port_mmaps_t *mmaps, nxt_chunk_id_t *c,
446699Smax.romanov@nginx.com     nxt_int_t n, nxt_bool_t tracking)
44742Smax.romanov@nginx.com {
448699Smax.romanov@nginx.com     nxt_int_t                i, res, nchunks;
449423Smax.romanov@nginx.com     nxt_free_map_t           *free_map;
450365Smax.romanov@nginx.com     nxt_port_mmap_t          *port_mmap;
451365Smax.romanov@nginx.com     nxt_port_mmap_t          *end_port_mmap;
452365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
453365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
45442Smax.romanov@nginx.com 
4551546Smax.romanov@nginx.com     nxt_thread_mutex_lock(&mmaps->mutex);
45642Smax.romanov@nginx.com 
4571546Smax.romanov@nginx.com     end_port_mmap = mmaps->elts + mmaps->size;
45880Smax.romanov@nginx.com 
4591546Smax.romanov@nginx.com     for (port_mmap = mmaps->elts;
460365Smax.romanov@nginx.com          port_mmap < end_port_mmap;
461365Smax.romanov@nginx.com          port_mmap++)
462365Smax.romanov@nginx.com     {
463365Smax.romanov@nginx.com         mmap_handler = port_mmap->mmap_handler;
464365Smax.romanov@nginx.com         hdr = mmap_handler->hdr;
46580Smax.romanov@nginx.com 
4661546Smax.romanov@nginx.com         if (hdr->sent_over != 0xFFFFu) {
467365Smax.romanov@nginx.com             continue;
468365Smax.romanov@nginx.com         }
469365Smax.romanov@nginx.com 
470699Smax.romanov@nginx.com         *c = 0;
471699Smax.romanov@nginx.com 
472423Smax.romanov@nginx.com         free_map = tracking ? hdr->free_tracking_map : hdr->free_map;
473423Smax.romanov@nginx.com 
474699Smax.romanov@nginx.com         while (nxt_port_mmap_get_free_chunk(free_map, c)) {
475699Smax.romanov@nginx.com             nchunks = 1;
476699Smax.romanov@nginx.com 
477699Smax.romanov@nginx.com             while (nchunks < n) {
478699Smax.romanov@nginx.com                 res = nxt_port_mmap_chk_set_chunk_busy(free_map, *c + nchunks);
479699Smax.romanov@nginx.com 
480699Smax.romanov@nginx.com                 if (res == 0) {
481699Smax.romanov@nginx.com                     for (i = 0; i < nchunks; i++) {
482699Smax.romanov@nginx.com                         nxt_port_mmap_set_chunk_free(free_map, *c + i);
483699Smax.romanov@nginx.com                     }
484699Smax.romanov@nginx.com 
485699Smax.romanov@nginx.com                     *c += nchunks + 1;
486699Smax.romanov@nginx.com                     nchunks = 0;
487699Smax.romanov@nginx.com                     break;
488699Smax.romanov@nginx.com                 }
489699Smax.romanov@nginx.com 
490699Smax.romanov@nginx.com                 nchunks++;
491699Smax.romanov@nginx.com             }
492699Smax.romanov@nginx.com 
493699Smax.romanov@nginx.com             if (nchunks == n) {
494699Smax.romanov@nginx.com                 goto unlock_return;
495699Smax.romanov@nginx.com             }
49642Smax.romanov@nginx.com         }
4971321Smax.romanov@nginx.com 
4981321Smax.romanov@nginx.com         hdr->oosm = 1;
49942Smax.romanov@nginx.com     }
50042Smax.romanov@nginx.com 
50142Smax.romanov@nginx.com     /* TODO introduce port_mmap limit and release wait. */
50280Smax.romanov@nginx.com 
503699Smax.romanov@nginx.com     *c = 0;
5041546Smax.romanov@nginx.com     mmap_handler = nxt_port_new_port_mmap(task, mmaps, tracking, n);
50580Smax.romanov@nginx.com 
50680Smax.romanov@nginx.com unlock_return:
50780Smax.romanov@nginx.com 
5081546Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&mmaps->mutex);
50990Smax.romanov@nginx.com 
510365Smax.romanov@nginx.com     return mmap_handler;
51142Smax.romanov@nginx.com }
51242Smax.romanov@nginx.com 
51342Smax.romanov@nginx.com 
514365Smax.romanov@nginx.com static nxt_port_mmap_handler_t *
nxt_port_get_port_incoming_mmap(nxt_task_t * task,nxt_pid_t spid,uint32_t id)51542Smax.romanov@nginx.com nxt_port_get_port_incoming_mmap(nxt_task_t *task, nxt_pid_t spid, uint32_t id)
51642Smax.romanov@nginx.com {
517365Smax.romanov@nginx.com     nxt_process_t            *process;
518365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
51942Smax.romanov@nginx.com 
520196Smax.romanov@nginx.com     process = nxt_runtime_process_find(task->thread->runtime, spid);
52142Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
52242Smax.romanov@nginx.com         return NULL;
52342Smax.romanov@nginx.com     }
52442Smax.romanov@nginx.com 
525364Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
52680Smax.romanov@nginx.com 
527364Smax.romanov@nginx.com     if (nxt_fast_path(process->incoming.size > id)) {
528365Smax.romanov@nginx.com         mmap_handler = process->incoming.elts[id].mmap_handler;
529423Smax.romanov@nginx.com 
530423Smax.romanov@nginx.com     } else {
531423Smax.romanov@nginx.com         mmap_handler = NULL;
532423Smax.romanov@nginx.com 
533423Smax.romanov@nginx.com         nxt_debug(task, "invalid incoming mmap id %uD for pid %PI", id, spid);
53442Smax.romanov@nginx.com     }
53542Smax.romanov@nginx.com 
536364Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
53790Smax.romanov@nginx.com 
538365Smax.romanov@nginx.com     return mmap_handler;
53942Smax.romanov@nginx.com }
54042Smax.romanov@nginx.com 
54142Smax.romanov@nginx.com 
54242Smax.romanov@nginx.com nxt_buf_t *
nxt_port_mmap_get_buf(nxt_task_t * task,nxt_port_mmaps_t * mmaps,size_t size)5431546Smax.romanov@nginx.com nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_mmaps_t *mmaps, size_t size)
54442Smax.romanov@nginx.com {
545430Sigor@sysoev.ru     nxt_mp_t                 *mp;
546365Smax.romanov@nginx.com     nxt_buf_t                *b;
547699Smax.romanov@nginx.com     nxt_int_t                nchunks;
548365Smax.romanov@nginx.com     nxt_chunk_id_t           c;
549365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
550365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
55142Smax.romanov@nginx.com 
55242Smax.romanov@nginx.com     nxt_debug(task, "request %z bytes shm buffer", size);
55342Smax.romanov@nginx.com 
554699Smax.romanov@nginx.com     nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE;
555699Smax.romanov@nginx.com 
556699Smax.romanov@nginx.com     if (nxt_slow_path(nchunks > PORT_MMAP_CHUNK_COUNT)) {
557699Smax.romanov@nginx.com         nxt_alert(task, "requested buffer (%z) too big", size);
558699Smax.romanov@nginx.com 
559699Smax.romanov@nginx.com         return NULL;
560699Smax.romanov@nginx.com     }
561699Smax.romanov@nginx.com 
562342Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 0);
56342Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
56442Smax.romanov@nginx.com         return NULL;
56542Smax.romanov@nginx.com     }
56642Smax.romanov@nginx.com 
56742Smax.romanov@nginx.com     b->completion_handler = nxt_port_mmap_buf_completion;
56842Smax.romanov@nginx.com     nxt_buf_set_port_mmap(b);
56942Smax.romanov@nginx.com 
5701546Smax.romanov@nginx.com     mmap_handler = nxt_port_mmap_get(task, mmaps, &c, nchunks, 0);
571365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
572430Sigor@sysoev.ru         mp = task->thread->engine->mem_pool;
573430Sigor@sysoev.ru         nxt_mp_free(mp, b);
574430Sigor@sysoev.ru         nxt_mp_release(mp);
57542Smax.romanov@nginx.com         return NULL;
57642Smax.romanov@nginx.com     }
57742Smax.romanov@nginx.com 
578365Smax.romanov@nginx.com     b->parent = mmap_handler;
579365Smax.romanov@nginx.com 
580365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
581365Smax.romanov@nginx.com 
582365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
583122Smax.romanov@nginx.com 
58480Smax.romanov@nginx.com     b->mem.start = nxt_port_mmap_chunk_start(hdr, c);
58542Smax.romanov@nginx.com     b->mem.pos = b->mem.start;
58642Smax.romanov@nginx.com     b->mem.free = b->mem.start;
587699Smax.romanov@nginx.com     b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE;
58842Smax.romanov@nginx.com 
589494Spluknet@nginx.com     nxt_debug(task, "outgoing mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d",
590363Smax.romanov@nginx.com               b, b->mem.start, b->mem.end - b->mem.start,
591363Smax.romanov@nginx.com               hdr->src_pid, hdr->dst_pid, hdr->id, c);
592206Smax.romanov@nginx.com 
59342Smax.romanov@nginx.com     return b;
59442Smax.romanov@nginx.com }
59542Smax.romanov@nginx.com 
59642Smax.romanov@nginx.com 
59780Smax.romanov@nginx.com nxt_int_t
nxt_port_mmap_increase_buf(nxt_task_t * task,nxt_buf_t * b,size_t size,size_t min_size)598206Smax.romanov@nginx.com nxt_port_mmap_increase_buf(nxt_task_t *task, nxt_buf_t *b, size_t size,
599206Smax.romanov@nginx.com     size_t min_size)
60080Smax.romanov@nginx.com {
601365Smax.romanov@nginx.com     size_t                   nchunks, free_size;
602365Smax.romanov@nginx.com     nxt_chunk_id_t           c, start;
603365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
604365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
60580Smax.romanov@nginx.com 
60680Smax.romanov@nginx.com     nxt_debug(task, "request increase %z bytes shm buffer", size);
60780Smax.romanov@nginx.com 
60880Smax.romanov@nginx.com     if (nxt_slow_path(nxt_buf_is_port_mmap(b) == 0)) {
60980Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN,
61080Smax.romanov@nginx.com                 "failed to increase, not a mmap buffer");
61180Smax.romanov@nginx.com         return NXT_ERROR;
61280Smax.romanov@nginx.com     }
61380Smax.romanov@nginx.com 
614206Smax.romanov@nginx.com     free_size = nxt_buf_mem_free_size(&b->mem);
615206Smax.romanov@nginx.com 
616206Smax.romanov@nginx.com     if (nxt_slow_path(size <= free_size)) {
61780Smax.romanov@nginx.com         return NXT_OK;
61880Smax.romanov@nginx.com     }
61980Smax.romanov@nginx.com 
620365Smax.romanov@nginx.com     mmap_handler = b->parent;
621365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
62280Smax.romanov@nginx.com 
62380Smax.romanov@nginx.com     start = nxt_port_mmap_chunk_id(hdr, b->mem.end);
62480Smax.romanov@nginx.com 
625206Smax.romanov@nginx.com     size -= free_size;
62680Smax.romanov@nginx.com 
627723Smax.romanov@nginx.com     nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE;
62880Smax.romanov@nginx.com 
62980Smax.romanov@nginx.com     c = start;
63080Smax.romanov@nginx.com 
63180Smax.romanov@nginx.com     /* Try to acquire as much chunks as required. */
63280Smax.romanov@nginx.com     while (nchunks > 0) {
63380Smax.romanov@nginx.com 
634423Smax.romanov@nginx.com         if (nxt_port_mmap_chk_set_chunk_busy(hdr->free_map, c) == 0) {
63580Smax.romanov@nginx.com             break;
63680Smax.romanov@nginx.com         }
63780Smax.romanov@nginx.com 
63880Smax.romanov@nginx.com         c++;
63980Smax.romanov@nginx.com         nchunks--;
640