xref: /unit/src/nxt_port_memory.c (revision 1008)
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 
20364Smax.romanov@nginx.com nxt_inline void
21365Smax.romanov@nginx.com nxt_port_mmap_handler_use(nxt_port_mmap_handler_t *mmap_handler, int i)
2242Smax.romanov@nginx.com {
23613Svbart@nginx.com     int  c;
24365Smax.romanov@nginx.com 
25365Smax.romanov@nginx.com     c = nxt_atomic_fetch_add(&mmap_handler->use_count, i);
26365Smax.romanov@nginx.com 
27365Smax.romanov@nginx.com     if (i < 0 && c == -i) {
28365Smax.romanov@nginx.com         if (mmap_handler->hdr != NULL) {
29365Smax.romanov@nginx.com             nxt_mem_munmap(mmap_handler->hdr, PORT_MMAP_SIZE);
30365Smax.romanov@nginx.com             mmap_handler->hdr = NULL;
31365Smax.romanov@nginx.com         }
32365Smax.romanov@nginx.com 
33365Smax.romanov@nginx.com         nxt_free(mmap_handler);
3442Smax.romanov@nginx.com     }
3542Smax.romanov@nginx.com }
3642Smax.romanov@nginx.com 
3742Smax.romanov@nginx.com 
38364Smax.romanov@nginx.com static nxt_port_mmap_t *
39364Smax.romanov@nginx.com nxt_port_mmap_at(nxt_port_mmaps_t *port_mmaps, uint32_t i)
40141Smax.romanov@nginx.com {
41364Smax.romanov@nginx.com     uint32_t  cap;
42141Smax.romanov@nginx.com 
43364Smax.romanov@nginx.com     cap = port_mmaps->cap;
44141Smax.romanov@nginx.com 
45364Smax.romanov@nginx.com     if (cap == 0) {
46364Smax.romanov@nginx.com         cap = i + 1;
47141Smax.romanov@nginx.com     }
48141Smax.romanov@nginx.com 
49364Smax.romanov@nginx.com     while (i + 1 > cap) {
50364Smax.romanov@nginx.com 
51364Smax.romanov@nginx.com         if (cap < 16) {
52*1008Szelenkov@nginx.com             cap = cap * 2;
53141Smax.romanov@nginx.com 
54364Smax.romanov@nginx.com         } else {
55*1008Szelenkov@nginx.com             cap = cap + cap / 2;
56364Smax.romanov@nginx.com         }
57364Smax.romanov@nginx.com     }
58364Smax.romanov@nginx.com 
59364Smax.romanov@nginx.com     if (cap != port_mmaps->cap) {
60141Smax.romanov@nginx.com 
61364Smax.romanov@nginx.com         port_mmaps->elts = nxt_realloc(port_mmaps->elts,
62364Smax.romanov@nginx.com                                        cap * sizeof(nxt_port_mmap_t));
63364Smax.romanov@nginx.com         if (nxt_slow_path(port_mmaps->elts == NULL)) {
64364Smax.romanov@nginx.com             return NULL;
65364Smax.romanov@nginx.com         }
66364Smax.romanov@nginx.com 
67364Smax.romanov@nginx.com         nxt_memzero(port_mmaps->elts + port_mmaps->cap,
68364Smax.romanov@nginx.com                     sizeof(nxt_port_mmap_t) * (cap - port_mmaps->cap));
69141Smax.romanov@nginx.com 
70364Smax.romanov@nginx.com         port_mmaps->cap = cap;
71364Smax.romanov@nginx.com     }
72364Smax.romanov@nginx.com 
73364Smax.romanov@nginx.com     if (i + 1 > port_mmaps->size) {
74364Smax.romanov@nginx.com         port_mmaps->size = i + 1;
75364Smax.romanov@nginx.com     }
76364Smax.romanov@nginx.com 
77364Smax.romanov@nginx.com     return port_mmaps->elts + i;
78141Smax.romanov@nginx.com }
79141Smax.romanov@nginx.com 
80141Smax.romanov@nginx.com 
81141Smax.romanov@nginx.com void
82365Smax.romanov@nginx.com nxt_port_mmaps_destroy(nxt_port_mmaps_t *port_mmaps, nxt_bool_t free_elts)
83141Smax.romanov@nginx.com {
84141Smax.romanov@nginx.com     uint32_t         i;
85141Smax.romanov@nginx.com     nxt_port_mmap_t  *port_mmap;
86141Smax.romanov@nginx.com 
87141Smax.romanov@nginx.com     if (port_mmaps == NULL) {
88141Smax.romanov@nginx.com         return;
89141Smax.romanov@nginx.com     }
90141Smax.romanov@nginx.com 
91141Smax.romanov@nginx.com     port_mmap = port_mmaps->elts;
92141Smax.romanov@nginx.com 
93364Smax.romanov@nginx.com     for (i = 0; i < port_mmaps->size; i++) {
94365Smax.romanov@nginx.com         nxt_port_mmap_handler_use(port_mmap[i].mmap_handler, -1);
95141Smax.romanov@nginx.com     }
96141Smax.romanov@nginx.com 
97364Smax.romanov@nginx.com     port_mmaps->size = 0;
98141Smax.romanov@nginx.com 
99365Smax.romanov@nginx.com     if (free_elts != 0) {
100364Smax.romanov@nginx.com         nxt_free(port_mmaps->elts);
101141Smax.romanov@nginx.com     }
102141Smax.romanov@nginx.com }
103141Smax.romanov@nginx.com 
104141Smax.romanov@nginx.com 
105195Smax.romanov@nginx.com #define nxt_port_mmap_free_junk(p, size)                                      \
106195Smax.romanov@nginx.com     memset((p), 0xA5, size)
107195Smax.romanov@nginx.com 
108195Smax.romanov@nginx.com 
10942Smax.romanov@nginx.com static void
11042Smax.romanov@nginx.com nxt_port_mmap_buf_completion(nxt_task_t *task, void *obj, void *data)
11142Smax.romanov@nginx.com {
112365Smax.romanov@nginx.com     u_char                   *p;
113365Smax.romanov@nginx.com     nxt_mp_t                 *mp;
114365Smax.romanov@nginx.com     nxt_buf_t                *b;
115365Smax.romanov@nginx.com     nxt_chunk_id_t           c;
116365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
117365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
11842Smax.romanov@nginx.com 
119122Smax.romanov@nginx.com     if (nxt_buf_ts_handle(task, obj, data)) {
120122Smax.romanov@nginx.com         return;
121122Smax.romanov@nginx.com     }
122122Smax.romanov@nginx.com 
12342Smax.romanov@nginx.com     b = obj;
12442Smax.romanov@nginx.com 
12542Smax.romanov@nginx.com     mp = b->data;
12642Smax.romanov@nginx.com 
127564Svbart@nginx.com     nxt_assert(data == b->parent);
12879Smax.romanov@nginx.com 
129365Smax.romanov@nginx.com     mmap_handler = data;
130365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
13142Smax.romanov@nginx.com 
132363Smax.romanov@nginx.com     if (nxt_slow_path(hdr->src_pid != nxt_pid && hdr->dst_pid != nxt_pid)) {
133363Smax.romanov@nginx.com         nxt_debug(task, "mmap buf completion: mmap for other process pair "
134363Smax.romanov@nginx.com                   "%PI->%PI", hdr->src_pid, hdr->dst_pid);
135363Smax.romanov@nginx.com 
136363Smax.romanov@nginx.com         goto release_buf;
137363Smax.romanov@nginx.com     }
138363Smax.romanov@nginx.com 
13942Smax.romanov@nginx.com     if (b->is_port_mmap_sent && b->mem.pos > b->mem.start) {
14042Smax.romanov@nginx.com         /*
14142Smax.romanov@nginx.com          * Chunks until b->mem.pos has been sent to other side,
14242Smax.romanov@nginx.com          * let's release rest (if any).
14342Smax.romanov@nginx.com          */
14442Smax.romanov@nginx.com         p = b->mem.pos - 1;
14580Smax.romanov@nginx.com         c = nxt_port_mmap_chunk_id(hdr, p) + 1;
14680Smax.romanov@nginx.com         p = nxt_port_mmap_chunk_start(hdr, c);
147141Smax.romanov@nginx.com 
14842Smax.romanov@nginx.com     } else {
14942Smax.romanov@nginx.com         p = b->mem.start;
15080Smax.romanov@nginx.com         c = nxt_port_mmap_chunk_id(hdr, p);
15142Smax.romanov@nginx.com     }
15242Smax.romanov@nginx.com 
153195Smax.romanov@nginx.com     nxt_port_mmap_free_junk(p, b->mem.end - p);
154195Smax.romanov@nginx.com 
155494Spluknet@nginx.com     nxt_debug(task, "mmap buf completion: %p [%p,%uz] (sent=%d), "
156363Smax.romanov@nginx.com               "%PI->%PI,%d,%d", b, b->mem.start, b->mem.end - b->mem.start,
157363Smax.romanov@nginx.com               b->is_port_mmap_sent, hdr->src_pid, hdr->dst_pid, hdr->id, c);
158206Smax.romanov@nginx.com 
15942Smax.romanov@nginx.com     while (p < b->mem.end) {
160423Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_free(hdr->free_map, c);
16142Smax.romanov@nginx.com 
16242Smax.romanov@nginx.com         p += PORT_MMAP_CHUNK_SIZE;
16342Smax.romanov@nginx.com         c++;
16442Smax.romanov@nginx.com     }
16542Smax.romanov@nginx.com 
166363Smax.romanov@nginx.com release_buf:
167363Smax.romanov@nginx.com 
168365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, -1);
169365Smax.romanov@nginx.com 
170430Sigor@sysoev.ru     nxt_mp_free(mp, b);
171430Sigor@sysoev.ru     nxt_mp_release(mp);
17242Smax.romanov@nginx.com }
17342Smax.romanov@nginx.com 
17442Smax.romanov@nginx.com 
175365Smax.romanov@nginx.com nxt_port_mmap_handler_t *
17642Smax.romanov@nginx.com nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process,
17742Smax.romanov@nginx.com     nxt_fd_t fd)
17842Smax.romanov@nginx.com {
179365Smax.romanov@nginx.com     void                     *mem;
180365Smax.romanov@nginx.com     struct stat              mmap_stat;
181365Smax.romanov@nginx.com     nxt_port_mmap_t          *port_mmap;
182365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
183365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
18442Smax.romanov@nginx.com 
18542Smax.romanov@nginx.com     nxt_debug(task, "got new mmap fd #%FD from process %PI",
18642Smax.romanov@nginx.com               fd, process->pid);
18742Smax.romanov@nginx.com 
18880Smax.romanov@nginx.com     port_mmap = NULL;
18980Smax.romanov@nginx.com 
19042Smax.romanov@nginx.com     if (fstat(fd, &mmap_stat) == -1) {
19142Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "fstat(%FD) failed %E", fd, nxt_errno);
19242Smax.romanov@nginx.com 
19342Smax.romanov@nginx.com         return NULL;
19442Smax.romanov@nginx.com     }
19542Smax.romanov@nginx.com 
19680Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, mmap_stat.st_size,
19780Smax.romanov@nginx.com                        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
19842Smax.romanov@nginx.com 
19980Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
20042Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "mmap() failed %E", nxt_errno);
20142Smax.romanov@nginx.com 
202364Smax.romanov@nginx.com         return NULL;
20342Smax.romanov@nginx.com     }
20442Smax.romanov@nginx.com 
205364Smax.romanov@nginx.com     hdr = mem;
206364Smax.romanov@nginx.com 
207365Smax.romanov@nginx.com     mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t));
208365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
209365Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "failed to allocate mmap_handler");
210365Smax.romanov@nginx.com 
211382Smax.romanov@nginx.com         nxt_mem_munmap(mem, PORT_MMAP_SIZE);
212382Smax.romanov@nginx.com 
213365Smax.romanov@nginx.com         return NULL;
214365Smax.romanov@nginx.com     }
215365Smax.romanov@nginx.com 
216365Smax.romanov@nginx.com     mmap_handler->hdr = hdr;
217365Smax.romanov@nginx.com 
218551Smax.romanov@nginx.com     if (nxt_slow_path(hdr->src_pid != process->pid
219551Smax.romanov@nginx.com                       || hdr->dst_pid != nxt_pid))
220551Smax.romanov@nginx.com     {
221551Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "unexpected pid in mmap header detected: "
222551Smax.romanov@nginx.com                 "%PI != %PI or %PI != %PI", hdr->src_pid, process->pid,
223551Smax.romanov@nginx.com                 hdr->dst_pid, nxt_pid);
224551Smax.romanov@nginx.com 
225551Smax.romanov@nginx.com         return NULL;
226551Smax.romanov@nginx.com     }
227551Smax.romanov@nginx.com 
228364Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
22980Smax.romanov@nginx.com 
230364Smax.romanov@nginx.com     port_mmap = nxt_port_mmap_at(&process->incoming, hdr->id);
231364Smax.romanov@nginx.com     if (nxt_slow_path(port_mmap == NULL)) {
232364Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "failed to add mmap to incoming array");
233364Smax.romanov@nginx.com 
234364Smax.romanov@nginx.com         nxt_mem_munmap(mem, PORT_MMAP_SIZE);
235364Smax.romanov@nginx.com         hdr = NULL;
236364Smax.romanov@nginx.com 
237365Smax.romanov@nginx.com         nxt_free(mmap_handler);
238365Smax.romanov@nginx.com         mmap_handler = NULL;
239365Smax.romanov@nginx.com 
240364Smax.romanov@nginx.com         goto fail;
24180Smax.romanov@nginx.com     }
24280Smax.romanov@nginx.com 
243365Smax.romanov@nginx.com     port_mmap->mmap_handler = mmap_handler;
244365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
245364Smax.romanov@nginx.com 
246323Smax.romanov@nginx.com     hdr->sent_over = 0xFFFFu;
247323Smax.romanov@nginx.com 
24880Smax.romanov@nginx.com fail:
24980Smax.romanov@nginx.com 
250364Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
25190Smax.romanov@nginx.com 
252365Smax.romanov@nginx.com     return mmap_handler;
25342Smax.romanov@nginx.com }
25442Smax.romanov@nginx.com 
25542Smax.romanov@nginx.com 
256365Smax.romanov@nginx.com static nxt_port_mmap_handler_t *
25742Smax.romanov@nginx.com nxt_port_new_port_mmap(nxt_task_t *task, nxt_process_t *process,
258743Smax.romanov@nginx.com     nxt_port_t *port, nxt_bool_t tracking, nxt_int_t n)
25942Smax.romanov@nginx.com {
260365Smax.romanov@nginx.com     void                     *mem;
261365Smax.romanov@nginx.com     u_char                   *p, name[64];
262365Smax.romanov@nginx.com     nxt_fd_t                 fd;
263723Smax.romanov@nginx.com     nxt_int_t                i;
264423Smax.romanov@nginx.com     nxt_free_map_t           *free_map;
265365Smax.romanov@nginx.com     nxt_port_mmap_t          *port_mmap;
266365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
267365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
268365Smax.romanov@nginx.com 
269365Smax.romanov@nginx.com     mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t));
270365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
271365Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "failed to allocate mmap_handler");
272365Smax.romanov@nginx.com 
273365Smax.romanov@nginx.com         return NULL;
274365Smax.romanov@nginx.com     }
27542Smax.romanov@nginx.com 
276364Smax.romanov@nginx.com     port_mmap = nxt_port_mmap_at(&process->outgoing, process->outgoing.size);
27742Smax.romanov@nginx.com     if (nxt_slow_path(port_mmap == NULL)) {
27842Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN,
27942Smax.romanov@nginx.com                 "failed to add port mmap to outgoing array");
28042Smax.romanov@nginx.com 
281365Smax.romanov@nginx.com         nxt_free(mmap_handler);
28242Smax.romanov@nginx.com         return NULL;
28342Smax.romanov@nginx.com     }
28442Smax.romanov@nginx.com 
285461Sigor@sysoev.ru     p = nxt_sprintf(name, name + sizeof(name), NXT_SHM_PREFIX "unit.%PI.%uxD",
286138Sigor@sysoev.ru                     nxt_pid, nxt_random(&task->thread->random));
28742Smax.romanov@nginx.com     *p = '\0';
28842Smax.romanov@nginx.com 
28942Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE)
290277Sigor@sysoev.ru 
29180Smax.romanov@nginx.com     fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC);
29242Smax.romanov@nginx.com 
29380Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
294564Svbart@nginx.com         nxt_alert(task, "memfd_create(%s) failed %E", name, nxt_errno);
29542Smax.romanov@nginx.com 
29642Smax.romanov@nginx.com         goto remove_fail;
29742Smax.romanov@nginx.com     }
29842Smax.romanov@nginx.com 
29980Smax.romanov@nginx.com     nxt_debug(task, "memfd_create(%s): %FD", name, fd);
30042Smax.romanov@nginx.com 
301566Spluknet@nginx.com #elif (NXT_HAVE_SHM_OPEN_ANON)
302566Spluknet@nginx.com 
303566Spluknet@nginx.com     fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR);
304566Spluknet@nginx.com 
305566Spluknet@nginx.com     nxt_debug(task, "shm_open(SHM_ANON): %FD", fd);
306566Spluknet@nginx.com 
307566Spluknet@nginx.com     if (nxt_slow_path(fd == -1)) {
308566Spluknet@nginx.com         nxt_alert(task, "shm_open(SHM_ANON) failed %E", nxt_errno);
309566Spluknet@nginx.com 
310566Spluknet@nginx.com         goto remove_fail;
311566Spluknet@nginx.com     }
312566Spluknet@nginx.com 
31342Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN)
314277Sigor@sysoev.ru 
315277Sigor@sysoev.ru     /* Just in case. */
316277Sigor@sysoev.ru     shm_unlink((char *) name);
31742Smax.romanov@nginx.com 
31880Smax.romanov@nginx.com     fd = shm_open((char *) name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
31942Smax.romanov@nginx.com 
32080Smax.romanov@nginx.com     nxt_debug(task, "shm_open(%s): %FD", name, fd);
32142Smax.romanov@nginx.com 
32280Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
323564Svbart@nginx.com         nxt_alert(task, "shm_open(%s) failed %E", name, nxt_errno);
32442Smax.romanov@nginx.com 
32542Smax.romanov@nginx.com         goto remove_fail;
32642Smax.romanov@nginx.com     }
32742Smax.romanov@nginx.com 
32842Smax.romanov@nginx.com     if (nxt_slow_path(shm_unlink((char *) name) == -1)) {
32942Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "shm_unlink(%s) failed %E", name,
33042Smax.romanov@nginx.com                 nxt_errno);
33142Smax.romanov@nginx.com     }
332277Sigor@sysoev.ru 
333378Svbart@nginx.com #else
334378Svbart@nginx.com 
335378Svbart@nginx.com #error No working shared memory implementation.
336378Svbart@nginx.com 
33742Smax.romanov@nginx.com #endif
33842Smax.romanov@nginx.com 
33980Smax.romanov@nginx.com     if (nxt_slow_path(ftruncate(fd, PORT_MMAP_SIZE) == -1)) {
34042Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "ftruncate() failed %E", nxt_errno);
34142Smax.romanov@nginx.com 
34242Smax.romanov@nginx.com         goto remove_fail;
34342Smax.romanov@nginx.com     }
34442Smax.romanov@nginx.com 
345277Sigor@sysoev.ru     mem = nxt_mem_mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE,
346277Sigor@sysoev.ru                        MAP_SHARED, fd, 0);
34742Smax.romanov@nginx.com 
34880Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
34942Smax.romanov@nginx.com         goto remove_fail;
35042Smax.romanov@nginx.com     }
35142Smax.romanov@nginx.com 
352365Smax.romanov@nginx.com     mmap_handler->hdr = mem;
353365Smax.romanov@nginx.com     port_mmap->mmap_handler = mmap_handler;
354365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
35580Smax.romanov@nginx.com 
35642Smax.romanov@nginx.com     /* Init segment header. */
357365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
35842Smax.romanov@nginx.com 
35942Smax.romanov@nginx.com     nxt_memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map));
360423Smax.romanov@nginx.com     nxt_memset(hdr->free_tracking_map, 0xFFU, sizeof(hdr->free_tracking_map));
36142Smax.romanov@nginx.com 
362364Smax.romanov@nginx.com     hdr->id = process->outgoing.size - 1;
363363Smax.romanov@nginx.com     hdr->src_pid = nxt_pid;
364363Smax.romanov@nginx.com     hdr->dst_pid = process->pid;
365323Smax.romanov@nginx.com     hdr->sent_over = port->id;
36680Smax.romanov@nginx.com 
36780Smax.romanov@nginx.com     /* Mark first chunk as busy */
368423Smax.romanov@nginx.com     free_map = tracking ? hdr->free_tracking_map : hdr->free_map;
369423Smax.romanov@nginx.com 
370723Smax.romanov@nginx.com     for (i = 0; i < n; i++) {
371723Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_busy(free_map, i);
372723Smax.romanov@nginx.com     }
37380Smax.romanov@nginx.com 
37442Smax.romanov@nginx.com     /* Mark as busy chunk followed the last available chunk. */
375423Smax.romanov@nginx.com     nxt_port_mmap_set_chunk_busy(hdr->free_map, PORT_MMAP_CHUNK_COUNT);
376423Smax.romanov@nginx.com     nxt_port_mmap_set_chunk_busy(hdr->free_tracking_map, PORT_MMAP_CHUNK_COUNT);
37742Smax.romanov@nginx.com 
378363Smax.romanov@nginx.com     nxt_debug(task, "send mmap fd %FD to process %PI", fd, port->pid);
37942Smax.romanov@nginx.com 
38042Smax.romanov@nginx.com     /* TODO handle error */
381189Smax.romanov@nginx.com     (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL);
38242Smax.romanov@nginx.com 
38342Smax.romanov@nginx.com     nxt_log(task, NXT_LOG_DEBUG, "new mmap #%D created for %PI -> %PI",
38480Smax.romanov@nginx.com             hdr->id, nxt_pid, process->pid);
38542Smax.romanov@nginx.com 
386365Smax.romanov@nginx.com     return mmap_handler;
38742Smax.romanov@nginx.com 
38842Smax.romanov@nginx.com remove_fail:
38942Smax.romanov@nginx.com 
390365Smax.romanov@nginx.com     nxt_free(mmap_handler);
391365Smax.romanov@nginx.com 
392364Smax.romanov@nginx.com     process->outgoing.size--;
39342Smax.romanov@nginx.com 
39442Smax.romanov@nginx.com     return NULL;
39542Smax.romanov@nginx.com }
39642Smax.romanov@nginx.com 
39742Smax.romanov@nginx.com 
398365Smax.romanov@nginx.com static nxt_port_mmap_handler_t *
39942Smax.romanov@nginx.com nxt_port_mmap_get(nxt_task_t *task, nxt_port_t *port, nxt_chunk_id_t *c,
400699Smax.romanov@nginx.com     nxt_int_t n, nxt_bool_t tracking)
40142Smax.romanov@nginx.com {
402699Smax.romanov@nginx.com     nxt_int_t                i, res, nchunks;
403365Smax.romanov@nginx.com     nxt_process_t            *process;
404423Smax.romanov@nginx.com     nxt_free_map_t           *free_map;
405365Smax.romanov@nginx.com     nxt_port_mmap_t          *port_mmap;
406365Smax.romanov@nginx.com     nxt_port_mmap_t          *end_port_mmap;
407365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
408365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
40942Smax.romanov@nginx.com 
41080Smax.romanov@nginx.com     process = port->process;
41142Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
41242Smax.romanov@nginx.com         return NULL;
41342Smax.romanov@nginx.com     }
41442Smax.romanov@nginx.com 
415364Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->outgoing.mutex);
41680Smax.romanov@nginx.com 
417365Smax.romanov@nginx.com     end_port_mmap = process->outgoing.elts + process->outgoing.size;
41842Smax.romanov@nginx.com 
419365Smax.romanov@nginx.com     for (port_mmap = process->outgoing.elts;
420365Smax.romanov@nginx.com          port_mmap < end_port_mmap;
421365Smax.romanov@nginx.com          port_mmap++)
422365Smax.romanov@nginx.com     {
423365Smax.romanov@nginx.com         mmap_handler = port_mmap->mmap_handler;
424365Smax.romanov@nginx.com         hdr = mmap_handler->hdr;
42580Smax.romanov@nginx.com 
426365Smax.romanov@nginx.com         if (hdr->sent_over != 0xFFFFu && hdr->sent_over != port->id) {
427365Smax.romanov@nginx.com             continue;
428365Smax.romanov@nginx.com         }
429365Smax.romanov@nginx.com 
430699Smax.romanov@nginx.com         *c = 0;
431699Smax.romanov@nginx.com 
432423Smax.romanov@nginx.com         free_map = tracking ? hdr->free_tracking_map : hdr->free_map;
433423Smax.romanov@nginx.com 
434699Smax.romanov@nginx.com         while (nxt_port_mmap_get_free_chunk(free_map, c)) {
435699Smax.romanov@nginx.com             nchunks = 1;
436699Smax.romanov@nginx.com 
437699Smax.romanov@nginx.com             while (nchunks < n) {
438699Smax.romanov@nginx.com                 res = nxt_port_mmap_chk_set_chunk_busy(free_map, *c + nchunks);
439699Smax.romanov@nginx.com 
440699Smax.romanov@nginx.com                 if (res == 0) {
441699Smax.romanov@nginx.com                     for (i = 0; i < nchunks; i++) {
442699Smax.romanov@nginx.com                         nxt_port_mmap_set_chunk_free(free_map, *c + i);
443699Smax.romanov@nginx.com                     }
444699Smax.romanov@nginx.com 
445699Smax.romanov@nginx.com                     *c += nchunks + 1;
446699Smax.romanov@nginx.com                     nchunks = 0;
447699Smax.romanov@nginx.com                     break;
448699Smax.romanov@nginx.com                 }
449699Smax.romanov@nginx.com 
450699Smax.romanov@nginx.com                 nchunks++;
451699Smax.romanov@nginx.com             }
452699Smax.romanov@nginx.com 
453699Smax.romanov@nginx.com             if (nchunks == n) {
454699Smax.romanov@nginx.com                 goto unlock_return;
455699Smax.romanov@nginx.com             }
45642Smax.romanov@nginx.com         }
45742Smax.romanov@nginx.com     }
45842Smax.romanov@nginx.com 
45942Smax.romanov@nginx.com     /* TODO introduce port_mmap limit and release wait. */
46080Smax.romanov@nginx.com 
461699Smax.romanov@nginx.com     *c = 0;
462743Smax.romanov@nginx.com     mmap_handler = nxt_port_new_port_mmap(task, process, port, tracking, n);
46380Smax.romanov@nginx.com 
46480Smax.romanov@nginx.com unlock_return:
46580Smax.romanov@nginx.com 
466364Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->outgoing.mutex);
46790Smax.romanov@nginx.com 
468365Smax.romanov@nginx.com     return mmap_handler;
46942Smax.romanov@nginx.com }
47042Smax.romanov@nginx.com 
47142Smax.romanov@nginx.com 
472365Smax.romanov@nginx.com static nxt_port_mmap_handler_t *
47342Smax.romanov@nginx.com nxt_port_get_port_incoming_mmap(nxt_task_t *task, nxt_pid_t spid, uint32_t id)
47442Smax.romanov@nginx.com {
475365Smax.romanov@nginx.com     nxt_process_t            *process;
476365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
47742Smax.romanov@nginx.com 
478196Smax.romanov@nginx.com     process = nxt_runtime_process_find(task->thread->runtime, spid);
47942Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
48042Smax.romanov@nginx.com         return NULL;
48142Smax.romanov@nginx.com     }
48242Smax.romanov@nginx.com 
483364Smax.romanov@nginx.com     nxt_thread_mutex_lock(&process->incoming.mutex);
48480Smax.romanov@nginx.com 
485364Smax.romanov@nginx.com     if (nxt_fast_path(process->incoming.size > id)) {
486365Smax.romanov@nginx.com         mmap_handler = process->incoming.elts[id].mmap_handler;
487423Smax.romanov@nginx.com 
488423Smax.romanov@nginx.com     } else {
489423Smax.romanov@nginx.com         mmap_handler = NULL;
490423Smax.romanov@nginx.com 
491423Smax.romanov@nginx.com         nxt_debug(task, "invalid incoming mmap id %uD for pid %PI", id, spid);
49242Smax.romanov@nginx.com     }
49342Smax.romanov@nginx.com 
494364Smax.romanov@nginx.com     nxt_thread_mutex_unlock(&process->incoming.mutex);
49590Smax.romanov@nginx.com 
496365Smax.romanov@nginx.com     return mmap_handler;
49742Smax.romanov@nginx.com }
49842Smax.romanov@nginx.com 
49942Smax.romanov@nginx.com 
500423Smax.romanov@nginx.com nxt_int_t
501423Smax.romanov@nginx.com nxt_port_mmap_get_tracking(nxt_task_t *task, nxt_port_t *port,
502423Smax.romanov@nginx.com     nxt_port_mmap_tracking_t *tracking, uint32_t stream)
503423Smax.romanov@nginx.com {
504423Smax.romanov@nginx.com     nxt_chunk_id_t           c;
505423Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
506423Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
507423Smax.romanov@nginx.com 
508423Smax.romanov@nginx.com     nxt_debug(task, "request tracking for stream #%uD", stream);
509423Smax.romanov@nginx.com 
510699Smax.romanov@nginx.com     mmap_handler = nxt_port_mmap_get(task, port, &c, 1, 1);
511423Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
512423Smax.romanov@nginx.com         return NXT_ERROR;
513423Smax.romanov@nginx.com     }
514423Smax.romanov@nginx.com 
515423Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
516423Smax.romanov@nginx.com 
517423Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
518423Smax.romanov@nginx.com 
519423Smax.romanov@nginx.com     tracking->mmap_handler = mmap_handler;
520423Smax.romanov@nginx.com     tracking->tracking = hdr->tracking + c;
521423Smax.romanov@nginx.com 
522423Smax.romanov@nginx.com     *tracking->tracking = stream;
523423Smax.romanov@nginx.com 
524423Smax.romanov@nginx.com     nxt_debug(task, "outgoing tracking allocation: %PI->%PI,%d,%d",
525423Smax.romanov@nginx.com               hdr->src_pid, hdr->dst_pid, hdr->id, c);
526423Smax.romanov@nginx.com 
527423Smax.romanov@nginx.com     return NXT_OK;
528423Smax.romanov@nginx.com }
529423Smax.romanov@nginx.com 
530423Smax.romanov@nginx.com 
531423Smax.romanov@nginx.com nxt_bool_t
532423Smax.romanov@nginx.com nxt_port_mmap_tracking_cancel(nxt_task_t *task,
533423Smax.romanov@nginx.com     nxt_port_mmap_tracking_t *tracking, uint32_t stream)
534423Smax.romanov@nginx.com {
535423Smax.romanov@nginx.com     nxt_bool_t               res;
536423Smax.romanov@nginx.com     nxt_chunk_id_t           c;
537423Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
538423Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
539423Smax.romanov@nginx.com 
540423Smax.romanov@nginx.com     mmap_handler = tracking->mmap_handler;
541423Smax.romanov@nginx.com 
542423Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
543423Smax.romanov@nginx.com         return 0;
544423Smax.romanov@nginx.com     }
545423Smax.romanov@nginx.com 
546423Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
547423Smax.romanov@nginx.com 
548423Smax.romanov@nginx.com     res = nxt_atomic_cmp_set(tracking->tracking, stream, 0);
549423Smax.romanov@nginx.com 
550423Smax.romanov@nginx.com     nxt_debug(task, "%s tracking for stream #%uD",
551423Smax.romanov@nginx.com               (res ? "cancelled" : "failed to cancel"), stream);
552423Smax.romanov@nginx.com 
553423Smax.romanov@nginx.com     if (!res) {
554423Smax.romanov@nginx.com         c = tracking->tracking - hdr->tracking;
555423Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_free(hdr->free_tracking_map, c);
556423Smax.romanov@nginx.com     }
557423Smax.romanov@nginx.com 
558423Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, -1);
559423Smax.romanov@nginx.com 
560423Smax.romanov@nginx.com     return res;
561423Smax.romanov@nginx.com }
562423Smax.romanov@nginx.com 
563423Smax.romanov@nginx.com 
564423Smax.romanov@nginx.com nxt_int_t
565423Smax.romanov@nginx.com nxt_port_mmap_tracking_write(uint32_t *buf, nxt_port_mmap_tracking_t *t)
566423Smax.romanov@nginx.com {
567423Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
568423Smax.romanov@nginx.com 
569423Smax.romanov@nginx.com     mmap_handler = t->mmap_handler;
570538Svbart@nginx.com 
571538Svbart@nginx.com #if (NXT_DEBUG)
572538Svbart@nginx.com     {
573538Svbart@nginx.com     nxt_atomic_t  *tracking;
574538Svbart@nginx.com 
575423Smax.romanov@nginx.com     tracking = mmap_handler->hdr->tracking;
576423Smax.romanov@nginx.com 
577423Smax.romanov@nginx.com     nxt_assert(t->tracking >= tracking);
578423Smax.romanov@nginx.com     nxt_assert(t->tracking < tracking + PORT_MMAP_CHUNK_COUNT);
579538Svbart@nginx.com     }
580538Svbart@nginx.com #endif
581423Smax.romanov@nginx.com 
582423Smax.romanov@nginx.com     buf[0] = mmap_handler->hdr->id;
583423Smax.romanov@nginx.com     buf[1] = t->tracking - mmap_handler->hdr->tracking;
584423Smax.romanov@nginx.com 
585423Smax.romanov@nginx.com     return NXT_OK;
586423Smax.romanov@nginx.com }
587423Smax.romanov@nginx.com 
588423Smax.romanov@nginx.com nxt_bool_t
589423Smax.romanov@nginx.com nxt_port_mmap_tracking_read(nxt_task_t *task, nxt_port_recv_msg_t *msg)
590423Smax.romanov@nginx.com {
591423Smax.romanov@nginx.com     nxt_buf_t                     *b;
592423Smax.romanov@nginx.com     nxt_bool_t                    res;
593423Smax.romanov@nginx.com     nxt_chunk_id_t                c;
594423Smax.romanov@nginx.com     nxt_port_mmap_header_t        *hdr;
595423Smax.romanov@nginx.com     nxt_port_mmap_handler_t       *mmap_handler;
596423Smax.romanov@nginx.com     nxt_port_mmap_tracking_msg_t  *tracking_msg;
597423Smax.romanov@nginx.com 
598423Smax.romanov@nginx.com     b = msg->buf;
599423Smax.romanov@nginx.com 
600521Szelenkov@nginx.com     if (nxt_buf_used_size(b) < (int) sizeof(nxt_port_mmap_tracking_msg_t)) {
601494Spluknet@nginx.com         nxt_debug(task, "too small message %O", nxt_buf_used_size(b));
602423Smax.romanov@nginx.com         return 0;
603423Smax.romanov@nginx.com     }
604423Smax.romanov@nginx.com 
605423Smax.romanov@nginx.com     tracking_msg = (nxt_port_mmap_tracking_msg_t *) b->mem.pos;
606423Smax.romanov@nginx.com 
607423Smax.romanov@nginx.com     b->mem.pos += sizeof(nxt_port_mmap_tracking_msg_t);
608423Smax.romanov@nginx.com     mmap_handler = nxt_port_get_port_incoming_mmap(task, msg->port_msg.pid,
609423Smax.romanov@nginx.com                                                    tracking_msg->mmap_id);
610423Smax.romanov@nginx.com 
611423Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
612423Smax.romanov@nginx.com         return 0;
613423Smax.romanov@nginx.com     }
614423Smax.romanov@nginx.com 
615423Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
616423Smax.romanov@nginx.com 
617423Smax.romanov@nginx.com     c = tracking_msg->tracking_id;
618423Smax.romanov@nginx.com     res = nxt_atomic_cmp_set(hdr->tracking + c, msg->port_msg.stream, 0);
619423Smax.romanov@nginx.com 
620423Smax.romanov@nginx.com     nxt_debug(task, "tracking for stream #%uD %s", msg->port_msg.stream,
621423Smax.romanov@nginx.com               (res ? "received" : "already cancelled"));
622423Smax.romanov@nginx.com 
623423Smax.romanov@nginx.com     if (!res) {
624423Smax.romanov@nginx.com         nxt_port_mmap_set_chunk_free(hdr->free_tracking_map, c);
625423Smax.romanov@nginx.com     }
626423Smax.romanov@nginx.com 
627423Smax.romanov@nginx.com     return res;
628423Smax.romanov@nginx.com }
629423Smax.romanov@nginx.com 
630423Smax.romanov@nginx.com 
63142Smax.romanov@nginx.com nxt_buf_t *
63242Smax.romanov@nginx.com nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_t *port, size_t size)
63342Smax.romanov@nginx.com {
634430Sigor@sysoev.ru     nxt_mp_t                 *mp;
635365Smax.romanov@nginx.com     nxt_buf_t                *b;
636699Smax.romanov@nginx.com     nxt_int_t                nchunks;
637365Smax.romanov@nginx.com     nxt_chunk_id_t           c;
638365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
639365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
64042Smax.romanov@nginx.com 
64142Smax.romanov@nginx.com     nxt_debug(task, "request %z bytes shm buffer", size);
64242Smax.romanov@nginx.com 
643699Smax.romanov@nginx.com     nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE;
644699Smax.romanov@nginx.com 
645699Smax.romanov@nginx.com     if (nxt_slow_path(nchunks > PORT_MMAP_CHUNK_COUNT)) {
646699Smax.romanov@nginx.com         nxt_alert(task, "requested buffer (%z) too big", size);
647699Smax.romanov@nginx.com 
648699Smax.romanov@nginx.com         return NULL;
649699Smax.romanov@nginx.com     }
650699Smax.romanov@nginx.com 
651342Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 0);
65242Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
65342Smax.romanov@nginx.com         return NULL;
65442Smax.romanov@nginx.com     }
65542Smax.romanov@nginx.com 
65642Smax.romanov@nginx.com     b->completion_handler = nxt_port_mmap_buf_completion;
65742Smax.romanov@nginx.com     nxt_buf_set_port_mmap(b);
65842Smax.romanov@nginx.com 
659699Smax.romanov@nginx.com     mmap_handler = nxt_port_mmap_get(task, port, &c, nchunks, 0);
660365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
661430Sigor@sysoev.ru         mp = task->thread->engine->mem_pool;
662430Sigor@sysoev.ru         nxt_mp_free(mp, b);
663430Sigor@sysoev.ru         nxt_mp_release(mp);
66442Smax.romanov@nginx.com         return NULL;
66542Smax.romanov@nginx.com     }
66642Smax.romanov@nginx.com 
667365Smax.romanov@nginx.com     b->parent = mmap_handler;
668365Smax.romanov@nginx.com 
669365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
670365Smax.romanov@nginx.com 
671365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
672122Smax.romanov@nginx.com 
67380Smax.romanov@nginx.com     b->mem.start = nxt_port_mmap_chunk_start(hdr, c);
67442Smax.romanov@nginx.com     b->mem.pos = b->mem.start;
67542Smax.romanov@nginx.com     b->mem.free = b->mem.start;
676699Smax.romanov@nginx.com     b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE;
67742Smax.romanov@nginx.com 
678494Spluknet@nginx.com     nxt_debug(task, "outgoing mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d",
679363Smax.romanov@nginx.com               b, b->mem.start, b->mem.end - b->mem.start,
680363Smax.romanov@nginx.com               hdr->src_pid, hdr->dst_pid, hdr->id, c);
681206Smax.romanov@nginx.com 
68242Smax.romanov@nginx.com     return b;
68342Smax.romanov@nginx.com }
68442Smax.romanov@nginx.com 
68542Smax.romanov@nginx.com 
68680Smax.romanov@nginx.com nxt_int_t
687206Smax.romanov@nginx.com nxt_port_mmap_increase_buf(nxt_task_t *task, nxt_buf_t *b, size_t size,
688206Smax.romanov@nginx.com     size_t min_size)
68980Smax.romanov@nginx.com {
690365Smax.romanov@nginx.com     size_t                   nchunks, free_size;
691365Smax.romanov@nginx.com     nxt_chunk_id_t           c, start;
692365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
693365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
69480Smax.romanov@nginx.com 
69580Smax.romanov@nginx.com     nxt_debug(task, "request increase %z bytes shm buffer", size);
69680Smax.romanov@nginx.com 
69780Smax.romanov@nginx.com     if (nxt_slow_path(nxt_buf_is_port_mmap(b) == 0)) {
69880Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN,
69980Smax.romanov@nginx.com                 "failed to increase, not a mmap buffer");
70080Smax.romanov@nginx.com         return NXT_ERROR;
70180Smax.romanov@nginx.com     }
70280Smax.romanov@nginx.com 
703206Smax.romanov@nginx.com     free_size = nxt_buf_mem_free_size(&b->mem);
704206Smax.romanov@nginx.com 
705206Smax.romanov@nginx.com     if (nxt_slow_path(size <= free_size)) {
70680Smax.romanov@nginx.com         return NXT_OK;
70780Smax.romanov@nginx.com     }
70880Smax.romanov@nginx.com 
709365Smax.romanov@nginx.com     mmap_handler = b->parent;
710365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
71180Smax.romanov@nginx.com 
71280Smax.romanov@nginx.com     start = nxt_port_mmap_chunk_id(hdr, b->mem.end);
71380Smax.romanov@nginx.com 
714206Smax.romanov@nginx.com     size -= free_size;
71580Smax.romanov@nginx.com 
716723Smax.romanov@nginx.com     nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE;
71780Smax.romanov@nginx.com 
71880Smax.romanov@nginx.com     c = start;
71980Smax.romanov@nginx.com 
72080Smax.romanov@nginx.com     /* Try to acquire as much chunks as required. */
72180Smax.romanov@nginx.com     while (nchunks > 0) {
72280Smax.romanov@nginx.com 
723423Smax.romanov@nginx.com         if (nxt_port_mmap_chk_set_chunk_busy(hdr->free_map, c) == 0) {
72480Smax.romanov@nginx.com             break;
72580Smax.romanov@nginx.com         }
72680Smax.romanov@nginx.com 
72780Smax.romanov@nginx.com         c++;
72880Smax.romanov@nginx.com         nchunks--;
72980Smax.romanov@nginx.com     }
73080Smax.romanov@nginx.com 
731277Sigor@sysoev.ru     if (nchunks != 0
732277Sigor@sysoev.ru         && min_size > free_size + PORT_MMAP_CHUNK_SIZE * (c - start))
733277Sigor@sysoev.ru     {
73480Smax.romanov@nginx.com         c--;
73580Smax.romanov@nginx.com         while (c >= start) {
736423Smax.romanov@nginx.com             nxt_port_mmap_set_chunk_free(hdr->free_map, c);
73780Smax.romanov@nginx.com             c--;
73880Smax.romanov@nginx.com         }
73980Smax.romanov@nginx.com 
740494Spluknet@nginx.com         nxt_debug(task, "failed to increase, %uz chunks busy", nchunks);
74180Smax.romanov@nginx.com 
74280Smax.romanov@nginx.com         return NXT_ERROR;
743277Sigor@sysoev.ru 
74480Smax.romanov@nginx.com     } else {
74580Smax.romanov@nginx.com         b->mem.end += PORT_MMAP_CHUNK_SIZE * (c - start);
74680Smax.romanov@nginx.com 
74780Smax.romanov@nginx.com         return NXT_OK;
74880Smax.romanov@nginx.com     }
74980Smax.romanov@nginx.com }
75080Smax.romanov@nginx.com 
75180Smax.romanov@nginx.com 
75242Smax.romanov@nginx.com static nxt_buf_t *
75342Smax.romanov@nginx.com nxt_port_mmap_get_incoming_buf(nxt_task_t *task, nxt_port_t *port,
75442Smax.romanov@nginx.com     nxt_pid_t spid, nxt_port_mmap_msg_t *mmap_msg)
75542Smax.romanov@nginx.com {
756365Smax.romanov@nginx.com     size_t                   nchunks;
757365Smax.romanov@nginx.com     nxt_buf_t                *b;
758365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
759365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
76080Smax.romanov@nginx.com 
761365Smax.romanov@nginx.com     mmap_handler = nxt_port_get_port_incoming_mmap(task, spid,
762365Smax.romanov@nginx.com                                                    mmap_msg->mmap_id);
763365Smax.romanov@nginx.com     if (nxt_slow_path(mmap_handler == NULL)) {
76480Smax.romanov@nginx.com         return NULL;
76580Smax.romanov@nginx.com     }
76642Smax.romanov@nginx.com 
767122Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, port->mem_pool, 0);
76842Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
76942Smax.romanov@nginx.com         return NULL;
77042Smax.romanov@nginx.com     }
77142Smax.romanov@nginx.com 
77242Smax.romanov@nginx.com     b->completion_handler = nxt_port_mmap_buf_completion;
77342Smax.romanov@nginx.com 
77442Smax.romanov@nginx.com     nxt_buf_set_port_mmap(b);
77542Smax.romanov@nginx.com 
77642Smax.romanov@nginx.com     nchunks = mmap_msg->size / PORT_MMAP_CHUNK_SIZE;
77742Smax.romanov@nginx.com     if ((mmap_msg->size % PORT_MMAP_CHUNK_SIZE) != 0) {
77842Smax.romanov@nginx.com         nchunks++;
77942Smax.romanov@nginx.com     }
78042Smax.romanov@nginx.com 
781365Smax.romanov@nginx.com     hdr = mmap_handler->hdr;
782365Smax.romanov@nginx.com 
78380Smax.romanov@nginx.com     b->mem.start = nxt_port_mmap_chunk_start(hdr, mmap_msg->chunk_id);
78442Smax.romanov@nginx.com     b->mem.pos = b->mem.start;
78542Smax.romanov@nginx.com     b->mem.free = b->mem.start + mmap_msg->size;
78642Smax.romanov@nginx.com     b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE;
78742Smax.romanov@nginx.com 
788365Smax.romanov@nginx.com     b->parent = mmap_handler;
789365Smax.romanov@nginx.com     nxt_port_mmap_handler_use(mmap_handler, 1);
79042Smax.romanov@nginx.com 
791494Spluknet@nginx.com     nxt_debug(task, "incoming mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d",
792277Sigor@sysoev.ru               b, b->mem.start, b->mem.end - b->mem.start,
793363Smax.romanov@nginx.com               hdr->src_pid, hdr->dst_pid, hdr->id, mmap_msg->chunk_id);
794206Smax.romanov@nginx.com 
79542Smax.romanov@nginx.com     return b;
79642Smax.romanov@nginx.com }
79742Smax.romanov@nginx.com 
79842Smax.romanov@nginx.com 
79942Smax.romanov@nginx.com void
80042Smax.romanov@nginx.com nxt_port_mmap_write(nxt_task_t *task, nxt_port_t *port,
80142Smax.romanov@nginx.com     nxt_port_send_msg_t *msg, nxt_sendbuf_coalesce_t *sb)
80242Smax.romanov@nginx.com {
803365Smax.romanov@nginx.com     size_t                   bsize;
804365Smax.romanov@nginx.com     nxt_buf_t                *bmem;
805365Smax.romanov@nginx.com     nxt_uint_t               i;
806365Smax.romanov@nginx.com     nxt_port_mmap_msg_t      *mmap_msg;
807365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
808365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
80942Smax.romanov@nginx.com 
81042Smax.romanov@nginx.com     nxt_debug(task, "prepare %z bytes message for transfer to process %PI "
811277Sigor@sysoev.ru                     "via shared memory", sb->size, port->pid);
81242Smax.romanov@nginx.com 
81342Smax.romanov@nginx.com     bsize = sb->niov * sizeof(nxt_port_mmap_msg_t);
814197Smax.romanov@nginx.com     mmap_msg = port->mmsg_buf;
81542Smax.romanov@nginx.com 
81642Smax.romanov@nginx.com     bmem = msg->buf;
81742Smax.romanov@nginx.com 
81842Smax.romanov@nginx.com     for (i = 0; i < sb->niov; i++, mmap_msg++) {
81942Smax.romanov@nginx.com 
82042Smax.romanov@nginx.com         /* Lookup buffer which starts current iov_base. */
82142Smax.romanov@nginx.com         while (bmem && sb->iobuf[i].iov_base != bmem->mem.pos) {
82242Smax.romanov@nginx.com             bmem = bmem->next;
82342Smax.romanov@nginx.com         }
82442Smax.romanov@nginx.com 
82542Smax.romanov@nginx.com         if (nxt_slow_path(bmem == NULL)) {
826277Sigor@sysoev.ru             nxt_log_error(NXT_LOG_ERR, task->log,
827277Sigor@sysoev.ru                           "failed to find buf for iobuf[%d]", i);
82842Smax.romanov@nginx.com             return;
82942Smax.romanov@nginx.com             /* TODO clear b and exit */
83042Smax.romanov@nginx.com         }
83142Smax.romanov@nginx.com 
832365Smax.romanov@nginx.com         mmap_handler = bmem->parent;
833365Smax.romanov@nginx.com         hdr = mmap_handler->hdr;
83442Smax.romanov@nginx.com 
83580Smax.romanov@nginx.com         mmap_msg->mmap_id = hdr->id;
83680Smax.romanov@nginx.com         mmap_msg->chunk_id = nxt_port_mmap_chunk_id(hdr, bmem->mem.pos);
83742Smax.romanov@nginx.com         mmap_msg->size = sb->iobuf[i].iov_len;
83842Smax.romanov@nginx.com 
83942Smax.romanov@nginx.com         nxt_debug(task, "mmap_msg={%D, %D, %D} to %PI",
84042Smax.romanov@nginx.com                   mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size,
84142Smax.romanov@nginx.com                   port->pid);
84242Smax.romanov@nginx.com     }
84342Smax.romanov@nginx.com 
844197Smax.romanov@nginx.com     sb->iobuf[0].iov_base = port->mmsg_buf;
84542Smax.romanov@nginx.com     sb->iobuf[0].iov_len = bsize;
84642Smax.romanov@nginx.com     sb->niov = 1;
84742Smax.romanov@nginx.com     sb->size = bsize;
84842Smax.romanov@nginx.com 
84942Smax.romanov@nginx.com     msg->port_msg.mmap = 1;
85042Smax.romanov@nginx.com }
85142Smax.romanov@nginx.com 
85242Smax.romanov@nginx.com 
85342Smax.romanov@nginx.com void
854423Smax.romanov@nginx.com nxt_port_mmap_read(nxt_task_t *task, nxt_port_recv_msg_t *msg)
85542Smax.romanov@nginx.com {
85642Smax.romanov@nginx.com     nxt_buf_t            *b, **pb;
85742Smax.romanov@nginx.com     nxt_port_mmap_msg_t  *end, *mmap_msg;
85842Smax.romanov@nginx.com 
85942Smax.romanov@nginx.com     pb = &msg->buf;
86082Smax.romanov@nginx.com     msg->size = 0;
86142Smax.romanov@nginx.com 
862423Smax.romanov@nginx.com     for (b = msg->buf; b != NULL; b = b->next) {
863423Smax.romanov@nginx.com 
864423Smax.romanov@nginx.com         mmap_msg = (nxt_port_mmap_msg_t *) b->mem.pos;
865423Smax.romanov@nginx.com         end = (nxt_port_mmap_msg_t *) b->mem.free;
86642Smax.romanov@nginx.com 
867423Smax.romanov@nginx.com         while (mmap_msg < end) {
868423Smax.romanov@nginx.com             nxt_debug(task, "mmap_msg={%D, %D, %D} from %PI",
869423Smax.romanov@nginx.com                       mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size,
870423Smax.romanov@nginx.com                       msg->port_msg.pid);
87142Smax.romanov@nginx.com 
872423Smax.romanov@nginx.com             *pb = nxt_port_mmap_get_incoming_buf(task, msg->port,
873423Smax.romanov@nginx.com                                                  msg->port_msg.pid, mmap_msg);
874423Smax.romanov@nginx.com             if (nxt_slow_path(*pb == NULL)) {
875423Smax.romanov@nginx.com                 nxt_log_error(NXT_LOG_ERR, task->log,
876423Smax.romanov@nginx.com                               "failed to get mmap buffer");
877423Smax.romanov@nginx.com 
878423Smax.romanov@nginx.com                 break;
879423Smax.romanov@nginx.com             }
88042Smax.romanov@nginx.com 
881423Smax.romanov@nginx.com             msg->size += mmap_msg->size;
882423Smax.romanov@nginx.com             pb = &(*pb)->next;
883423Smax.romanov@nginx.com             mmap_msg++;
884423Smax.romanov@nginx.com 
885423Smax.romanov@nginx.com             /* Mark original buf as complete. */
886423Smax.romanov@nginx.com             b->mem.pos += sizeof(nxt_port_mmap_msg_t);
887423Smax.romanov@nginx.com         }
88842Smax.romanov@nginx.com     }
88942Smax.romanov@nginx.com }
89042Smax.romanov@nginx.com 
89142Smax.romanov@nginx.com 
89242Smax.romanov@nginx.com nxt_port_method_t
89342Smax.romanov@nginx.com nxt_port_mmap_get_method(nxt_task_t *task, nxt_port_t *port, nxt_buf_t *b)
89442Smax.romanov@nginx.com {
895365Smax.romanov@nginx.com     nxt_port_method_t        m;
896365Smax.romanov@nginx.com     nxt_port_mmap_header_t   *hdr;
897365Smax.romanov@nginx.com     nxt_port_mmap_handler_t  *mmap_handler;
89842Smax.romanov@nginx.com 
89942Smax.romanov@nginx.com     m = NXT_PORT_METHOD_ANY;
90042Smax.romanov@nginx.com 
901613Svbart@nginx.com     for (/* void */; b != NULL; b = b->next) {
90242Smax.romanov@nginx.com         if (nxt_buf_used_size(b) == 0) {
90342Smax.romanov@nginx.com             /* empty buffers does not affect method */
90442Smax.romanov@nginx.com             continue;
90542Smax.romanov@nginx.com         }
90642Smax.romanov@nginx.com 
90742Smax.romanov@nginx.com         if (nxt_buf_is_port_mmap(b)) {
908365Smax.romanov@nginx.com             mmap_handler = b->parent;
909365Smax.romanov@nginx.com             hdr = mmap_handler->hdr;
91042Smax.romanov@nginx.com 
91142Smax.romanov@nginx.com             if (m == NXT_PORT_METHOD_PLAIN) {
91242Smax.romanov@nginx.com                 nxt_log_error(NXT_LOG_ERR, task->log,
91342Smax.romanov@nginx.com                               "mixing plain and mmap buffers, "
91442Smax.romanov@nginx.com                               "using plain mode");
91542Smax.romanov@nginx.com 
91642Smax.romanov@nginx.com                 break;
91742Smax.romanov@nginx.com             }
91842Smax.romanov@nginx.com 
919363Smax.romanov@nginx.com             if (port->pid != hdr->dst_pid) {
92042Smax.romanov@nginx.com                 nxt_log_error(NXT_LOG_ERR, task->log,
92142Smax.romanov@nginx.com                               "send mmap buffer for %PI to %PI, "
922363Smax.romanov@nginx.com                               "using plain mode", hdr->dst_pid, port->pid);
92342Smax.romanov@nginx.com 
92442Smax.romanov@nginx.com                 m = NXT_PORT_METHOD_PLAIN;
92542Smax.romanov@nginx.com 
92642Smax.romanov@nginx.com                 break;
92742Smax.romanov@nginx.com             }
92842Smax.romanov@nginx.com 
92942Smax.romanov@nginx.com             if (m == NXT_PORT_METHOD_ANY) {
93042Smax.romanov@nginx.com                 nxt_debug(task, "using mmap mode");
93142Smax.romanov@nginx.com 
93242Smax.romanov@nginx.com                 m = NXT_PORT_METHOD_MMAP;
93342Smax.romanov@nginx.com             }
93442Smax.romanov@nginx.com         } else {
93542Smax.romanov@nginx.com             if (m == NXT_PORT_METHOD_MMAP) {
93642Smax.romanov@nginx.com                 nxt_log_error(NXT_LOG_ERR, task->log,
93742Smax.romanov@nginx.com                               "mixing mmap and plain buffers, "
93842Smax.romanov@nginx.com                               "switching to plain mode");
93942Smax.romanov@nginx.com 
94042Smax.romanov@nginx.com                 m = NXT_PORT_METHOD_PLAIN;
94142Smax.romanov@nginx.com 
94242Smax.romanov@nginx.com                 break;
94342Smax.romanov@nginx.com             }
94442Smax.romanov@nginx.com 
94542Smax.romanov@nginx.com             if (m == NXT_PORT_METHOD_ANY) {
94642Smax.romanov@nginx.com                 nxt_debug(task, "using plain mode");
94742Smax.romanov@nginx.com 
94842Smax.romanov@nginx.com                 m = NXT_PORT_METHOD_PLAIN;
94942Smax.romanov@nginx.com             }
95042Smax.romanov@nginx.com         }
95142Smax.romanov@nginx.com     }
95242Smax.romanov@nginx.com 
95342Smax.romanov@nginx.com     return m;
95442Smax.romanov@nginx.com }
955