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) { 521008Szelenkov@nginx.com cap = cap * 2; 53141Smax.romanov@nginx.com 54364Smax.romanov@nginx.com } else { 551008Szelenkov@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; 1141455Smax.romanov@nginx.com nxt_buf_t *b, *next; 1151321Smax.romanov@nginx.com nxt_port_t *port; 1161321Smax.romanov@nginx.com nxt_process_t *process; 117365Smax.romanov@nginx.com nxt_chunk_id_t c; 118365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 119365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 12042Smax.romanov@nginx.com 121122Smax.romanov@nginx.com if (nxt_buf_ts_handle(task, obj, data)) { 122122Smax.romanov@nginx.com return; 123122Smax.romanov@nginx.com } 124122Smax.romanov@nginx.com 12542Smax.romanov@nginx.com b = obj; 12642Smax.romanov@nginx.com 127564Svbart@nginx.com nxt_assert(data == b->parent); 12879Smax.romanov@nginx.com 129365Smax.romanov@nginx.com mmap_handler = data; 1301455Smax.romanov@nginx.com 1311455Smax.romanov@nginx.com complete_buf: 1321455Smax.romanov@nginx.com 133365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 13442Smax.romanov@nginx.com 135363Smax.romanov@nginx.com if (nxt_slow_path(hdr->src_pid != nxt_pid && hdr->dst_pid != nxt_pid)) { 136363Smax.romanov@nginx.com nxt_debug(task, "mmap buf completion: mmap for other process pair " 137363Smax.romanov@nginx.com "%PI->%PI", hdr->src_pid, hdr->dst_pid); 138363Smax.romanov@nginx.com 139363Smax.romanov@nginx.com goto release_buf; 140363Smax.romanov@nginx.com } 141363Smax.romanov@nginx.com 14242Smax.romanov@nginx.com if (b->is_port_mmap_sent && b->mem.pos > b->mem.start) { 14342Smax.romanov@nginx.com /* 14442Smax.romanov@nginx.com * Chunks until b->mem.pos has been sent to other side, 14542Smax.romanov@nginx.com * let's release rest (if any). 14642Smax.romanov@nginx.com */ 14742Smax.romanov@nginx.com p = b->mem.pos - 1; 14880Smax.romanov@nginx.com c = nxt_port_mmap_chunk_id(hdr, p) + 1; 14980Smax.romanov@nginx.com p = nxt_port_mmap_chunk_start(hdr, c); 150141Smax.romanov@nginx.com 15142Smax.romanov@nginx.com } else { 15242Smax.romanov@nginx.com p = b->mem.start; 15380Smax.romanov@nginx.com c = nxt_port_mmap_chunk_id(hdr, p); 15442Smax.romanov@nginx.com } 15542Smax.romanov@nginx.com 156195Smax.romanov@nginx.com nxt_port_mmap_free_junk(p, b->mem.end - p); 157195Smax.romanov@nginx.com 158494Spluknet@nginx.com nxt_debug(task, "mmap buf completion: %p [%p,%uz] (sent=%d), " 159363Smax.romanov@nginx.com "%PI->%PI,%d,%d", b, b->mem.start, b->mem.end - b->mem.start, 160363Smax.romanov@nginx.com b->is_port_mmap_sent, hdr->src_pid, hdr->dst_pid, hdr->id, c); 161206Smax.romanov@nginx.com 16242Smax.romanov@nginx.com while (p < b->mem.end) { 163423Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(hdr->free_map, c); 16442Smax.romanov@nginx.com 16542Smax.romanov@nginx.com p += PORT_MMAP_CHUNK_SIZE; 16642Smax.romanov@nginx.com c++; 16742Smax.romanov@nginx.com } 16842Smax.romanov@nginx.com 1691321Smax.romanov@nginx.com if (hdr->dst_pid == nxt_pid 1701321Smax.romanov@nginx.com && nxt_atomic_cmp_set(&hdr->oosm, 1, 0)) 1711321Smax.romanov@nginx.com { 1721321Smax.romanov@nginx.com process = nxt_runtime_process_find(task->thread->runtime, hdr->src_pid); 1731321Smax.romanov@nginx.com 1741321Smax.romanov@nginx.com if (process != NULL && !nxt_queue_is_empty(&process->ports)) { 1751321Smax.romanov@nginx.com port = nxt_process_port_first(process); 1761321Smax.romanov@nginx.com 1771488St.nateldemoura@f5.com if (port->type == NXT_PROCESS_APP) { 1781321Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_SHM_ACK, 1791321Smax.romanov@nginx.com -1, 0, 0, NULL); 1801321Smax.romanov@nginx.com } 1811321Smax.romanov@nginx.com } 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 * 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 235365Smax.romanov@nginx.com mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t)); 236365Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 237365Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to allocate mmap_handler"); 238365Smax.romanov@nginx.com 239382Smax.romanov@nginx.com nxt_mem_munmap(mem, PORT_MMAP_SIZE); 240382Smax.romanov@nginx.com 241365Smax.romanov@nginx.com return NULL; 242365Smax.romanov@nginx.com } 243365Smax.romanov@nginx.com 244365Smax.romanov@nginx.com mmap_handler->hdr = hdr; 245365Smax.romanov@nginx.com 246551Smax.romanov@nginx.com if (nxt_slow_path(hdr->src_pid != process->pid 247551Smax.romanov@nginx.com || hdr->dst_pid != nxt_pid)) 248551Smax.romanov@nginx.com { 249551Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "unexpected pid in mmap header detected: " 250551Smax.romanov@nginx.com "%PI != %PI or %PI != %PI", hdr->src_pid, process->pid, 251551Smax.romanov@nginx.com hdr->dst_pid, nxt_pid); 252551Smax.romanov@nginx.com 253551Smax.romanov@nginx.com return NULL; 254551Smax.romanov@nginx.com } 255551Smax.romanov@nginx.com 256364Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 25780Smax.romanov@nginx.com 258364Smax.romanov@nginx.com port_mmap = nxt_port_mmap_at(&process->incoming, hdr->id); 259364Smax.romanov@nginx.com if (nxt_slow_path(port_mmap == NULL)) { 260364Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to add mmap to incoming array"); 261364Smax.romanov@nginx.com 262364Smax.romanov@nginx.com nxt_mem_munmap(mem, PORT_MMAP_SIZE); 263364Smax.romanov@nginx.com hdr = NULL; 264364Smax.romanov@nginx.com 265365Smax.romanov@nginx.com nxt_free(mmap_handler); 266365Smax.romanov@nginx.com mmap_handler = NULL; 267365Smax.romanov@nginx.com 268364Smax.romanov@nginx.com goto fail; 26980Smax.romanov@nginx.com } 27080Smax.romanov@nginx.com 271365Smax.romanov@nginx.com port_mmap->mmap_handler = mmap_handler; 272365Smax.romanov@nginx.com nxt_port_mmap_handler_use(mmap_handler, 1); 273364Smax.romanov@nginx.com 274323Smax.romanov@nginx.com hdr->sent_over = 0xFFFFu; 275323Smax.romanov@nginx.com 27680Smax.romanov@nginx.com fail: 27780Smax.romanov@nginx.com 278364Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 27990Smax.romanov@nginx.com 280365Smax.romanov@nginx.com return mmap_handler; 28142Smax.romanov@nginx.com } 28242Smax.romanov@nginx.com 28342Smax.romanov@nginx.com 284365Smax.romanov@nginx.com static nxt_port_mmap_handler_t * 285*1546Smax.romanov@nginx.com nxt_port_new_port_mmap(nxt_task_t *task, nxt_port_mmaps_t *mmaps, 286*1546Smax.romanov@nginx.com nxt_bool_t tracking, nxt_int_t n) 28742Smax.romanov@nginx.com { 288365Smax.romanov@nginx.com void *mem; 289365Smax.romanov@nginx.com nxt_fd_t fd; 290723Smax.romanov@nginx.com nxt_int_t i; 291423Smax.romanov@nginx.com nxt_free_map_t *free_map; 292365Smax.romanov@nginx.com nxt_port_mmap_t *port_mmap; 293365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 294365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 295365Smax.romanov@nginx.com 296365Smax.romanov@nginx.com mmap_handler = nxt_zalloc(sizeof(nxt_port_mmap_handler_t)); 297365Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 298*1546Smax.romanov@nginx.com nxt_alert(task, "failed to allocate mmap_handler"); 299365Smax.romanov@nginx.com 300365Smax.romanov@nginx.com return NULL; 301365Smax.romanov@nginx.com } 30242Smax.romanov@nginx.com 303*1546Smax.romanov@nginx.com port_mmap = nxt_port_mmap_at(mmaps, mmaps->size); 30442Smax.romanov@nginx.com if (nxt_slow_path(port_mmap == NULL)) { 305*1546Smax.romanov@nginx.com nxt_alert(task, "failed to add port mmap to mmaps array"); 30642Smax.romanov@nginx.com 307365Smax.romanov@nginx.com nxt_free(mmap_handler); 30842Smax.romanov@nginx.com return NULL; 30942Smax.romanov@nginx.com } 31042Smax.romanov@nginx.com 3111526Smax.romanov@nginx.com fd = nxt_shm_open(task, PORT_MMAP_SIZE); 312566Spluknet@nginx.com if (nxt_slow_path(fd == -1)) { 31342Smax.romanov@nginx.com goto remove_fail; 31442Smax.romanov@nginx.com } 31542Smax.romanov@nginx.com 316277Sigor@sysoev.ru mem = nxt_mem_mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE, 317277Sigor@sysoev.ru MAP_SHARED, fd, 0); 31842Smax.romanov@nginx.com 31980Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 32042Smax.romanov@nginx.com goto remove_fail; 32142Smax.romanov@nginx.com } 32242Smax.romanov@nginx.com 323365Smax.romanov@nginx.com mmap_handler->hdr = mem; 324*1546Smax.romanov@nginx.com mmap_handler->fd = fd; 325365Smax.romanov@nginx.com port_mmap->mmap_handler = mmap_handler; 326365Smax.romanov@nginx.com nxt_port_mmap_handler_use(mmap_handler, 1); 32780Smax.romanov@nginx.com 32842Smax.romanov@nginx.com /* Init segment header. */ 329365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 33042Smax.romanov@nginx.com 33142Smax.romanov@nginx.com nxt_memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map)); 332423Smax.romanov@nginx.com nxt_memset(hdr->free_tracking_map, 0xFFU, sizeof(hdr->free_tracking_map)); 33342Smax.romanov@nginx.com 334*1546Smax.romanov@nginx.com hdr->id = mmaps->size - 1; 335363Smax.romanov@nginx.com hdr->src_pid = nxt_pid; 336*1546Smax.romanov@nginx.com hdr->sent_over = 0xFFFFu; 33780Smax.romanov@nginx.com 33880Smax.romanov@nginx.com /* Mark first chunk as busy */ 339423Smax.romanov@nginx.com free_map = tracking ? hdr->free_tracking_map : hdr->free_map; 340423Smax.romanov@nginx.com 341723Smax.romanov@nginx.com for (i = 0; i < n; i++) { 342723Smax.romanov@nginx.com nxt_port_mmap_set_chunk_busy(free_map, i); 343723Smax.romanov@nginx.com } 34480Smax.romanov@nginx.com 34542Smax.romanov@nginx.com /* Mark as busy chunk followed the last available chunk. */ 346423Smax.romanov@nginx.com nxt_port_mmap_set_chunk_busy(hdr->free_map, PORT_MMAP_CHUNK_COUNT); 347423Smax.romanov@nginx.com nxt_port_mmap_set_chunk_busy(hdr->free_tracking_map, PORT_MMAP_CHUNK_COUNT); 34842Smax.romanov@nginx.com 349*1546Smax.romanov@nginx.com nxt_log(task, NXT_LOG_DEBUG, "new mmap #%D created for %PI -> ...", 350*1546Smax.romanov@nginx.com hdr->id, nxt_pid); 35142Smax.romanov@nginx.com 352365Smax.romanov@nginx.com return mmap_handler; 35342Smax.romanov@nginx.com 35442Smax.romanov@nginx.com remove_fail: 35542Smax.romanov@nginx.com 356365Smax.romanov@nginx.com nxt_free(mmap_handler); 357365Smax.romanov@nginx.com 358*1546Smax.romanov@nginx.com mmaps->size--; 35942Smax.romanov@nginx.com 36042Smax.romanov@nginx.com return NULL; 36142Smax.romanov@nginx.com } 36242Smax.romanov@nginx.com 36342Smax.romanov@nginx.com 3641526Smax.romanov@nginx.com nxt_int_t 3651526Smax.romanov@nginx.com nxt_shm_open(nxt_task_t *task, size_t size) 3661526Smax.romanov@nginx.com { 3671526Smax.romanov@nginx.com nxt_fd_t fd; 3681526Smax.romanov@nginx.com 3691526Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE || NXT_HAVE_SHM_OPEN) 3701526Smax.romanov@nginx.com 3711526Smax.romanov@nginx.com u_char *p, name[64]; 3721526Smax.romanov@nginx.com 3731526Smax.romanov@nginx.com p = nxt_sprintf(name, name + sizeof(name), NXT_SHM_PREFIX "unit.%PI.%uxD", 3741526Smax.romanov@nginx.com nxt_pid, nxt_random(&task->thread->random)); 3751526Smax.romanov@nginx.com *p = '\0'; 3761526Smax.romanov@nginx.com 3771526Smax.romanov@nginx.com #endif 3781526Smax.romanov@nginx.com 3791526Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE) 3801526Smax.romanov@nginx.com 3811526Smax.romanov@nginx.com fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC); 3821526Smax.romanov@nginx.com 3831526Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 3841526Smax.romanov@nginx.com nxt_alert(task, "memfd_create(%s) failed %E", name, nxt_errno); 3851526Smax.romanov@nginx.com 3861526Smax.romanov@nginx.com return -1; 3871526Smax.romanov@nginx.com } 3881526Smax.romanov@nginx.com 3891526Smax.romanov@nginx.com nxt_debug(task, "memfd_create(%s): %FD", name, fd); 3901526Smax.romanov@nginx.com 3911526Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN_ANON) 3921526Smax.romanov@nginx.com 3931526Smax.romanov@nginx.com fd = shm_open(SHM_ANON, O_RDWR, S_IRUSR | S_IWUSR); 3941526Smax.romanov@nginx.com 3951526Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 3961526Smax.romanov@nginx.com nxt_alert(task, "shm_open(SHM_ANON) failed %E", nxt_errno); 3971526Smax.romanov@nginx.com 3981526Smax.romanov@nginx.com return -1; 3991526Smax.romanov@nginx.com } 4001526Smax.romanov@nginx.com 4011526Smax.romanov@nginx.com nxt_debug(task, "shm_open(SHM_ANON): %FD", fd); 4021526Smax.romanov@nginx.com 4031526Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN) 4041526Smax.romanov@nginx.com 4051526Smax.romanov@nginx.com /* Just in case. */ 4061526Smax.romanov@nginx.com shm_unlink((char *) name); 4071526Smax.romanov@nginx.com 4081526Smax.romanov@nginx.com fd = shm_open((char *) name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); 4091526Smax.romanov@nginx.com 4101526Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 4111526Smax.romanov@nginx.com nxt_alert(task, "shm_open(%s) failed %E", name, nxt_errno); 4121526Smax.romanov@nginx.com 4131526Smax.romanov@nginx.com return -1; 4141526Smax.romanov@nginx.com } 4151526Smax.romanov@nginx.com 4161526Smax.romanov@nginx.com nxt_debug(task, "shm_open(%s): %FD", name, fd); 4171526Smax.romanov@nginx.com 4181526Smax.romanov@nginx.com if (nxt_slow_path(shm_unlink((char *) name) == -1)) { 4191526Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "shm_unlink(%s) failed %E", name, 4201526Smax.romanov@nginx.com nxt_errno); 4211526Smax.romanov@nginx.com } 4221526Smax.romanov@nginx.com 4231526Smax.romanov@nginx.com #else 4241526Smax.romanov@nginx.com 4251526Smax.romanov@nginx.com #error No working shared memory implementation. 4261526Smax.romanov@nginx.com 4271526Smax.romanov@nginx.com #endif 4281526Smax.romanov@nginx.com 4291526Smax.romanov@nginx.com if (nxt_slow_path(ftruncate(fd, size) == -1)) { 4301526Smax.romanov@nginx.com nxt_alert(task, "ftruncate() failed %E", nxt_errno); 4311526Smax.romanov@nginx.com 4321526Smax.romanov@nginx.com nxt_fd_close(fd); 4331526Smax.romanov@nginx.com 4341526Smax.romanov@nginx.com return -1; 4351526Smax.romanov@nginx.com } 4361526Smax.romanov@nginx.com 4371526Smax.romanov@nginx.com return fd; 4381526Smax.romanov@nginx.com } 4391526Smax.romanov@nginx.com 4401526Smax.romanov@nginx.com 441365Smax.romanov@nginx.com static nxt_port_mmap_handler_t * 442*1546Smax.romanov@nginx.com nxt_port_mmap_get(nxt_task_t *task, nxt_port_mmaps_t *mmaps, nxt_chunk_id_t *c, 443699Smax.romanov@nginx.com nxt_int_t n, nxt_bool_t tracking) 44442Smax.romanov@nginx.com { 445699Smax.romanov@nginx.com nxt_int_t i, res, nchunks; 446423Smax.romanov@nginx.com nxt_free_map_t *free_map; 447365Smax.romanov@nginx.com nxt_port_mmap_t *port_mmap; 448365Smax.romanov@nginx.com nxt_port_mmap_t *end_port_mmap; 449365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 450365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 45142Smax.romanov@nginx.com 452*1546Smax.romanov@nginx.com nxt_thread_mutex_lock(&mmaps->mutex); 45342Smax.romanov@nginx.com 454*1546Smax.romanov@nginx.com end_port_mmap = mmaps->elts + mmaps->size; 45580Smax.romanov@nginx.com 456*1546Smax.romanov@nginx.com for (port_mmap = mmaps->elts; 457365Smax.romanov@nginx.com port_mmap < end_port_mmap; 458365Smax.romanov@nginx.com port_mmap++) 459365Smax.romanov@nginx.com { 460365Smax.romanov@nginx.com mmap_handler = port_mmap->mmap_handler; 461365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 46280Smax.romanov@nginx.com 463*1546Smax.romanov@nginx.com if (hdr->sent_over != 0xFFFFu) { 464365Smax.romanov@nginx.com continue; 465365Smax.romanov@nginx.com } 466365Smax.romanov@nginx.com 467699Smax.romanov@nginx.com *c = 0; 468699Smax.romanov@nginx.com 469423Smax.romanov@nginx.com free_map = tracking ? hdr->free_tracking_map : hdr->free_map; 470423Smax.romanov@nginx.com 471699Smax.romanov@nginx.com while (nxt_port_mmap_get_free_chunk(free_map, c)) { 472699Smax.romanov@nginx.com nchunks = 1; 473699Smax.romanov@nginx.com 474699Smax.romanov@nginx.com while (nchunks < n) { 475699Smax.romanov@nginx.com res = nxt_port_mmap_chk_set_chunk_busy(free_map, *c + nchunks); 476699Smax.romanov@nginx.com 477699Smax.romanov@nginx.com if (res == 0) { 478699Smax.romanov@nginx.com for (i = 0; i < nchunks; i++) { 479699Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(free_map, *c + i); 480699Smax.romanov@nginx.com } 481699Smax.romanov@nginx.com 482699Smax.romanov@nginx.com *c += nchunks + 1; 483699Smax.romanov@nginx.com nchunks = 0; 484699Smax.romanov@nginx.com break; 485699Smax.romanov@nginx.com } 486699Smax.romanov@nginx.com 487699Smax.romanov@nginx.com nchunks++; 488699Smax.romanov@nginx.com } 489699Smax.romanov@nginx.com 490699Smax.romanov@nginx.com if (nchunks == n) { 491699Smax.romanov@nginx.com goto unlock_return; 492699Smax.romanov@nginx.com } 49342Smax.romanov@nginx.com } 4941321Smax.romanov@nginx.com 4951321Smax.romanov@nginx.com hdr->oosm = 1; 49642Smax.romanov@nginx.com } 49742Smax.romanov@nginx.com 49842Smax.romanov@nginx.com /* TODO introduce port_mmap limit and release wait. */ 49980Smax.romanov@nginx.com 500699Smax.romanov@nginx.com *c = 0; 501*1546Smax.romanov@nginx.com mmap_handler = nxt_port_new_port_mmap(task, mmaps, tracking, n); 50280Smax.romanov@nginx.com 50380Smax.romanov@nginx.com unlock_return: 50480Smax.romanov@nginx.com 505*1546Smax.romanov@nginx.com nxt_thread_mutex_unlock(&mmaps->mutex); 50690Smax.romanov@nginx.com 507365Smax.romanov@nginx.com return mmap_handler; 50842Smax.romanov@nginx.com } 50942Smax.romanov@nginx.com 51042Smax.romanov@nginx.com 511365Smax.romanov@nginx.com static nxt_port_mmap_handler_t * 51242Smax.romanov@nginx.com nxt_port_get_port_incoming_mmap(nxt_task_t *task, nxt_pid_t spid, uint32_t id) 51342Smax.romanov@nginx.com { 514365Smax.romanov@nginx.com nxt_process_t *process; 515365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 51642Smax.romanov@nginx.com 517196Smax.romanov@nginx.com process = nxt_runtime_process_find(task->thread->runtime, spid); 51842Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 51942Smax.romanov@nginx.com return NULL; 52042Smax.romanov@nginx.com } 52142Smax.romanov@nginx.com 522364Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 52380Smax.romanov@nginx.com 524364Smax.romanov@nginx.com if (nxt_fast_path(process->incoming.size > id)) { 525365Smax.romanov@nginx.com mmap_handler = process->incoming.elts[id].mmap_handler; 526423Smax.romanov@nginx.com 527423Smax.romanov@nginx.com } else { 528423Smax.romanov@nginx.com mmap_handler = NULL; 529423Smax.romanov@nginx.com 530423Smax.romanov@nginx.com nxt_debug(task, "invalid incoming mmap id %uD for pid %PI", id, spid); 53142Smax.romanov@nginx.com } 53242Smax.romanov@nginx.com 533364Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 53490Smax.romanov@nginx.com 535365Smax.romanov@nginx.com return mmap_handler; 53642Smax.romanov@nginx.com } 53742Smax.romanov@nginx.com 53842Smax.romanov@nginx.com 539423Smax.romanov@nginx.com nxt_int_t 540*1546Smax.romanov@nginx.com nxt_port_mmap_get_tracking(nxt_task_t *task, nxt_port_mmaps_t *mmaps, 541423Smax.romanov@nginx.com nxt_port_mmap_tracking_t *tracking, uint32_t stream) 542423Smax.romanov@nginx.com { 543423Smax.romanov@nginx.com nxt_chunk_id_t c; 544423Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 545423Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 546423Smax.romanov@nginx.com 547423Smax.romanov@nginx.com nxt_debug(task, "request tracking for stream #%uD", stream); 548423Smax.romanov@nginx.com 549*1546Smax.romanov@nginx.com mmap_handler = nxt_port_mmap_get(task, mmaps, &c, 1, 1); 550423Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 551423Smax.romanov@nginx.com return NXT_ERROR; 552423Smax.romanov@nginx.com } 553423Smax.romanov@nginx.com 554423Smax.romanov@nginx.com nxt_port_mmap_handler_use(mmap_handler, 1); 555423Smax.romanov@nginx.com 556423Smax.romanov@nginx.com hdr = mmap_handler->hdr; 557423Smax.romanov@nginx.com 558423Smax.romanov@nginx.com tracking->mmap_handler = mmap_handler; 559423Smax.romanov@nginx.com tracking->tracking = hdr->tracking + c; 560423Smax.romanov@nginx.com 561423Smax.romanov@nginx.com *tracking->tracking = stream; 562423Smax.romanov@nginx.com 563423Smax.romanov@nginx.com nxt_debug(task, "outgoing tracking allocation: %PI->%PI,%d,%d", 564423Smax.romanov@nginx.com hdr->src_pid, hdr->dst_pid, hdr->id, c); 565423Smax.romanov@nginx.com 566423Smax.romanov@nginx.com return NXT_OK; 567423Smax.romanov@nginx.com } 568423Smax.romanov@nginx.com 569423Smax.romanov@nginx.com 570423Smax.romanov@nginx.com nxt_bool_t 571423Smax.romanov@nginx.com nxt_port_mmap_tracking_cancel(nxt_task_t *task, 572423Smax.romanov@nginx.com nxt_port_mmap_tracking_t *tracking, uint32_t stream) 573423Smax.romanov@nginx.com { 574423Smax.romanov@nginx.com nxt_bool_t res; 575423Smax.romanov@nginx.com nxt_chunk_id_t c; 576423Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 577423Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 578423Smax.romanov@nginx.com 579423Smax.romanov@nginx.com mmap_handler = tracking->mmap_handler; 580423Smax.romanov@nginx.com 581423Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 582423Smax.romanov@nginx.com return 0; 583423Smax.romanov@nginx.com } 584423Smax.romanov@nginx.com 585423Smax.romanov@nginx.com hdr = mmap_handler->hdr; 586423Smax.romanov@nginx.com 587423Smax.romanov@nginx.com res = nxt_atomic_cmp_set(tracking->tracking, stream, 0); 588423Smax.romanov@nginx.com 589423Smax.romanov@nginx.com nxt_debug(task, "%s tracking for stream #%uD", 590423Smax.romanov@nginx.com (res ? "cancelled" : "failed to cancel"), stream); 591423Smax.romanov@nginx.com 592423Smax.romanov@nginx.com if (!res) { 593423Smax.romanov@nginx.com c = tracking->tracking - hdr->tracking; 594423Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(hdr->free_tracking_map, c); 595423Smax.romanov@nginx.com } 596423Smax.romanov@nginx.com 597423Smax.romanov@nginx.com nxt_port_mmap_handler_use(mmap_handler, -1); 598423Smax.romanov@nginx.com 599423Smax.romanov@nginx.com return res; 600423Smax.romanov@nginx.com } 601423Smax.romanov@nginx.com 602423Smax.romanov@nginx.com 603423Smax.romanov@nginx.com nxt_int_t 604423Smax.romanov@nginx.com nxt_port_mmap_tracking_write(uint32_t *buf, nxt_port_mmap_tracking_t *t) 605423Smax.romanov@nginx.com { 606423Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 607423Smax.romanov@nginx.com 608423Smax.romanov@nginx.com mmap_handler = t->mmap_handler; 609538Svbart@nginx.com 610538Svbart@nginx.com #if (NXT_DEBUG) 611538Svbart@nginx.com { 612538Svbart@nginx.com nxt_atomic_t *tracking; 613538Svbart@nginx.com 614423Smax.romanov@nginx.com tracking = mmap_handler->hdr->tracking; 615423Smax.romanov@nginx.com 616423Smax.romanov@nginx.com nxt_assert(t->tracking >= tracking); 617423Smax.romanov@nginx.com nxt_assert(t->tracking < tracking + PORT_MMAP_CHUNK_COUNT); 618538Svbart@nginx.com } 619538Svbart@nginx.com #endif 620423Smax.romanov@nginx.com 621423Smax.romanov@nginx.com buf[0] = mmap_handler->hdr->id; 622423Smax.romanov@nginx.com buf[1] = t->tracking - mmap_handler->hdr->tracking; 623423Smax.romanov@nginx.com 624423Smax.romanov@nginx.com return NXT_OK; 625423Smax.romanov@nginx.com } 626423Smax.romanov@nginx.com 627423Smax.romanov@nginx.com nxt_bool_t 628423Smax.romanov@nginx.com nxt_port_mmap_tracking_read(nxt_task_t *task, nxt_port_recv_msg_t *msg) 629423Smax.romanov@nginx.com { 630423Smax.romanov@nginx.com nxt_buf_t *b; 631423Smax.romanov@nginx.com nxt_bool_t res; 632423Smax.romanov@nginx.com nxt_chunk_id_t c; 633423Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 634423Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 635423Smax.romanov@nginx.com nxt_port_mmap_tracking_msg_t *tracking_msg; 636423Smax.romanov@nginx.com 637423Smax.romanov@nginx.com b = msg->buf; 638423Smax.romanov@nginx.com 639521Szelenkov@nginx.com if (nxt_buf_used_size(b) < (int) sizeof(nxt_port_mmap_tracking_msg_t)) { 640494Spluknet@nginx.com nxt_debug(task, "too small message %O", nxt_buf_used_size(b)); 641423Smax.romanov@nginx.com return 0; 642423Smax.romanov@nginx.com } 643423Smax.romanov@nginx.com 644423Smax.romanov@nginx.com tracking_msg = (nxt_port_mmap_tracking_msg_t *) b->mem.pos; 645423Smax.romanov@nginx.com 646423Smax.romanov@nginx.com b->mem.pos += sizeof(nxt_port_mmap_tracking_msg_t); 647423Smax.romanov@nginx.com mmap_handler = nxt_port_get_port_incoming_mmap(task, msg->port_msg.pid, 648423Smax.romanov@nginx.com tracking_msg->mmap_id); 649423Smax.romanov@nginx.com 650423Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 651423Smax.romanov@nginx.com return 0; 652423Smax.romanov@nginx.com } 653423Smax.romanov@nginx.com 654423Smax.romanov@nginx.com hdr = mmap_handler->hdr; 655423Smax.romanov@nginx.com 656423Smax.romanov@nginx.com c = tracking_msg->tracking_id; 657423Smax.romanov@nginx.com res = nxt_atomic_cmp_set(hdr->tracking + c, msg->port_msg.stream, 0); 658423Smax.romanov@nginx.com 659423Smax.romanov@nginx.com nxt_debug(task, "tracking for stream #%uD %s", msg->port_msg.stream, 660423Smax.romanov@nginx.com (res ? "received" : "already cancelled")); 661423Smax.romanov@nginx.com 662423Smax.romanov@nginx.com if (!res) { 663423Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(hdr->free_tracking_map, c); 664423Smax.romanov@nginx.com } 665423Smax.romanov@nginx.com 666423Smax.romanov@nginx.com return res; 667423Smax.romanov@nginx.com } 668423Smax.romanov@nginx.com 669423Smax.romanov@nginx.com 67042Smax.romanov@nginx.com nxt_buf_t * 671*1546Smax.romanov@nginx.com nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_mmaps_t *mmaps, size_t size) 67242Smax.romanov@nginx.com { 673430Sigor@sysoev.ru nxt_mp_t *mp; 674365Smax.romanov@nginx.com nxt_buf_t *b; 675699Smax.romanov@nginx.com nxt_int_t nchunks; 676365Smax.romanov@nginx.com nxt_chunk_id_t c; 677365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 678365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 67942Smax.romanov@nginx.com 68042Smax.romanov@nginx.com nxt_debug(task, "request %z bytes shm buffer", size); 68142Smax.romanov@nginx.com 682699Smax.romanov@nginx.com nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE; 683699Smax.romanov@nginx.com 684699Smax.romanov@nginx.com if (nxt_slow_path(nchunks > PORT_MMAP_CHUNK_COUNT)) { 685699Smax.romanov@nginx.com nxt_alert(task, "requested buffer (%z) too big", size); 686699Smax.romanov@nginx.com 687699Smax.romanov@nginx.com return NULL; 688699Smax.romanov@nginx.com } 689699Smax.romanov@nginx.com 690342Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 0); 69142Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 69242Smax.romanov@nginx.com return NULL; 69342Smax.romanov@nginx.com } 69442Smax.romanov@nginx.com 69542Smax.romanov@nginx.com b->completion_handler = nxt_port_mmap_buf_completion; 69642Smax.romanov@nginx.com nxt_buf_set_port_mmap(b); 69742Smax.romanov@nginx.com 698*1546Smax.romanov@nginx.com mmap_handler = nxt_port_mmap_get(task, mmaps, &c, nchunks, 0); 699365Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 700430Sigor@sysoev.ru mp = task->thread->engine->mem_pool; 701430Sigor@sysoev.ru nxt_mp_free(mp, b); 702430Sigor@sysoev.ru nxt_mp_release(mp); 70342Smax.romanov@nginx.com return NULL; 70442Smax.romanov@nginx.com } 70542Smax.romanov@nginx.com 706365Smax.romanov@nginx.com b->parent = mmap_handler; 707365Smax.romanov@nginx.com 708365Smax.romanov@nginx.com nxt_port_mmap_handler_use(mmap_handler, 1); 709365Smax.romanov@nginx.com 710365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 711122Smax.romanov@nginx.com 71280Smax.romanov@nginx.com b->mem.start = nxt_port_mmap_chunk_start(hdr, c); 71342Smax.romanov@nginx.com b->mem.pos = b->mem.start; 71442Smax.romanov@nginx.com b->mem.free = b->mem.start; 715699Smax.romanov@nginx.com b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE; 71642Smax.romanov@nginx.com 717494Spluknet@nginx.com nxt_debug(task, "outgoing mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d", 718363Smax.romanov@nginx.com b, b->mem.start, b->mem.end - b->mem.start, 719363Smax.romanov@nginx.com hdr->src_pid, hdr->dst_pid, hdr->id, c); 720206Smax.romanov@nginx.com 72142Smax.romanov@nginx.com return b; 72242Smax.romanov@nginx.com } 72342Smax.romanov@nginx.com 72442Smax.romanov@nginx.com 72580Smax.romanov@nginx.com nxt_int_t 726206Smax.romanov@nginx.com nxt_port_mmap_increase_buf(nxt_task_t *task, nxt_buf_t *b, size_t size, 727206Smax.romanov@nginx.com size_t min_size) 72880Smax.romanov@nginx.com { 729365Smax.romanov@nginx.com size_t nchunks, free_size; 730365Smax.romanov@nginx.com nxt_chunk_id_t c, start; 731365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 732365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 73380Smax.romanov@nginx.com 73480Smax.romanov@nginx.com nxt_debug(task, "request increase %z bytes shm buffer", size); 73580Smax.romanov@nginx.com 73680Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_is_port_mmap(b) == 0)) { 73780Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, 73880Smax.romanov@nginx.com "failed to increase, not a mmap buffer"); 73980Smax.romanov@nginx.com return NXT_ERROR; 74080Smax.romanov@nginx.com } 74180Smax.romanov@nginx.com 742206Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&b->mem); 743206Smax.romanov@nginx.com 744206Smax.romanov@nginx.com if (nxt_slow_path(size <= free_size)) { 74580Smax.romanov@nginx.com return NXT_OK; 74680Smax.romanov@nginx.com } 74780Smax.romanov@nginx.com 748365Smax.romanov@nginx.com mmap_handler = b->parent; 749365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 75080Smax.romanov@nginx.com 75180Smax.romanov@nginx.com start = nxt_port_mmap_chunk_id(hdr, b->mem.end); 75280Smax.romanov@nginx.com 753206Smax.romanov@nginx.com size -= free_size; 75480Smax.romanov@nginx.com 755723Smax.romanov@nginx.com nchunks = (size + PORT_MMAP_CHUNK_SIZE - 1) / PORT_MMAP_CHUNK_SIZE; 75680Smax.romanov@nginx.com 75780Smax.romanov@nginx.com c = start; 75880Smax.romanov@nginx.com 75980Smax.romanov@nginx.com /* Try to acquire as much chunks as required. */ 76080Smax.romanov@nginx.com while (nchunks > 0) { 76180Smax.romanov@nginx.com 762423Smax.romanov@nginx.com if (nxt_port_mmap_chk_set_chunk_busy(hdr->free_map, c) == 0) { 76380Smax.romanov@nginx.com break; 76480Smax.romanov@nginx.com } 76580Smax.romanov@nginx.com 76680Smax.romanov@nginx.com c++; 76780Smax.romanov@nginx.com nchunks--; 76880Smax.romanov@nginx.com } 76980Smax.romanov@nginx.com 770277Sigor@sysoev.ru if (nchunks != 0 771277Sigor@sysoev.ru && min_size > free_size + PORT_MMAP_CHUNK_SIZE * (c - start)) 772277Sigor@sysoev.ru { 77380Smax.romanov@nginx.com c--; 77480Smax.romanov@nginx.com while (c >= start) { 775423Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(hdr->free_map, c); 77680Smax.romanov@nginx.com c--; 77780Smax.romanov@nginx.com } 77880Smax.romanov@nginx.com 779494Spluknet@nginx.com nxt_debug(task, "failed to increase, %uz chunks busy", nchunks); 78080Smax.romanov@nginx.com 78180Smax.romanov@nginx.com return NXT_ERROR; 782277Sigor@sysoev.ru 78380Smax.romanov@nginx.com } else { 78480Smax.romanov@nginx.com b->mem.end += PORT_MMAP_CHUNK_SIZE * (c - start); 78580Smax.romanov@nginx.com 78680Smax.romanov@nginx.com return NXT_OK; 78780Smax.romanov@nginx.com } 78880Smax.romanov@nginx.com } 78980Smax.romanov@nginx.com 79080Smax.romanov@nginx.com 79142Smax.romanov@nginx.com static nxt_buf_t * 79242Smax.romanov@nginx.com nxt_port_mmap_get_incoming_buf(nxt_task_t *task, nxt_port_t *port, 79342Smax.romanov@nginx.com nxt_pid_t spid, nxt_port_mmap_msg_t *mmap_msg) 79442Smax.romanov@nginx.com { 795365Smax.romanov@nginx.com size_t nchunks; 796365Smax.romanov@nginx.com nxt_buf_t *b; 797365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 798365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 79980Smax.romanov@nginx.com 800365Smax.romanov@nginx.com mmap_handler = nxt_port_get_port_incoming_mmap(task, spid, 801365Smax.romanov@nginx.com mmap_msg->mmap_id); 802365Smax.romanov@nginx.com if (nxt_slow_path(mmap_handler == NULL)) { 80380Smax.romanov@nginx.com return NULL; 80480Smax.romanov@nginx.com } 80542Smax.romanov@nginx.com 806122Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, port->mem_pool, 0); 80742Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 80842Smax.romanov@nginx.com return NULL; 80942Smax.romanov@nginx.com } 81042Smax.romanov@nginx.com 81142Smax.romanov@nginx.com b->completion_handler = nxt_port_mmap_buf_completion; 81242Smax.romanov@nginx.com 81342Smax.romanov@nginx.com nxt_buf_set_port_mmap(b); 81442Smax.romanov@nginx.com 81542Smax.romanov@nginx.com nchunks = mmap_msg->size / PORT_MMAP_CHUNK_SIZE; 81642Smax.romanov@nginx.com if ((mmap_msg->size % PORT_MMAP_CHUNK_SIZE) != 0) { 81742Smax.romanov@nginx.com nchunks++; 81842Smax.romanov@nginx.com } 81942Smax.romanov@nginx.com 820365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 821365Smax.romanov@nginx.com 82280Smax.romanov@nginx.com b->mem.start = nxt_port_mmap_chunk_start(hdr, mmap_msg->chunk_id); 82342Smax.romanov@nginx.com b->mem.pos = b->mem.start; 82442Smax.romanov@nginx.com b->mem.free = b->mem.start + mmap_msg->size; 82542Smax.romanov@nginx.com b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE; 82642Smax.romanov@nginx.com 827365Smax.romanov@nginx.com b->parent = mmap_handler; 828365Smax.romanov@nginx.com nxt_port_mmap_handler_use(mmap_handler, 1); 82942Smax.romanov@nginx.com 830494Spluknet@nginx.com nxt_debug(task, "incoming mmap buf allocation: %p [%p,%uz] %PI->%PI,%d,%d", 831277Sigor@sysoev.ru b, b->mem.start, b->mem.end - b->mem.start, 832363Smax.romanov@nginx.com hdr->src_pid, hdr->dst_pid, hdr->id, mmap_msg->chunk_id); 833206Smax.romanov@nginx.com 83442Smax.romanov@nginx.com return b; 83542Smax.romanov@nginx.com } 83642Smax.romanov@nginx.com 83742Smax.romanov@nginx.com 83842Smax.romanov@nginx.com void 83942Smax.romanov@nginx.com nxt_port_mmap_write(nxt_task_t *task, nxt_port_t *port, 8401125Smax.romanov@nginx.com nxt_port_send_msg_t *msg, nxt_sendbuf_coalesce_t *sb, void *mmsg_buf) 84142Smax.romanov@nginx.com { 842365Smax.romanov@nginx.com size_t bsize; 843365Smax.romanov@nginx.com nxt_buf_t *bmem; 844365Smax.romanov@nginx.com nxt_uint_t i; 845365Smax.romanov@nginx.com nxt_port_mmap_msg_t *mmap_msg; 846365Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 847365Smax.romanov@nginx.com nxt_port_mmap_handler_t *mmap_handler; 84842Smax.romanov@nginx.com 84942Smax.romanov@nginx.com nxt_debug(task, "prepare %z bytes message for transfer to process %PI " 850277Sigor@sysoev.ru "via shared memory", sb->size, port->pid); 85142Smax.romanov@nginx.com 85242Smax.romanov@nginx.com bsize = sb->niov * sizeof(nxt_port_mmap_msg_t); 8531125Smax.romanov@nginx.com mmap_msg = mmsg_buf; 85442Smax.romanov@nginx.com 85542Smax.romanov@nginx.com bmem = msg->buf; 85642Smax.romanov@nginx.com 85742Smax.romanov@nginx.com for (i = 0; i < sb->niov; i++, mmap_msg++) { 85842Smax.romanov@nginx.com 85942Smax.romanov@nginx.com /* Lookup buffer which starts current iov_base. */ 86042Smax.romanov@nginx.com while (bmem && sb->iobuf[i].iov_base != bmem->mem.pos) { 86142Smax.romanov@nginx.com bmem = bmem->next; 86242Smax.romanov@nginx.com } 86342Smax.romanov@nginx.com 86442Smax.romanov@nginx.com if (nxt_slow_path(bmem == NULL)) { 865277Sigor@sysoev.ru nxt_log_error(NXT_LOG_ERR, task->log, 866277Sigor@sysoev.ru "failed to find buf for iobuf[%d]", i); 86742Smax.romanov@nginx.com return; 86842Smax.romanov@nginx.com /* TODO clear b and exit */ 86942Smax.romanov@nginx.com } 87042Smax.romanov@nginx.com 871365Smax.romanov@nginx.com mmap_handler = bmem->parent; 872365Smax.romanov@nginx.com hdr = mmap_handler->hdr; 87342Smax.romanov@nginx.com 87480Smax.romanov@nginx.com mmap_msg->mmap_id = hdr->id; 87580Smax.romanov@nginx.com mmap_msg->chunk_id = nxt_port_mmap_chunk_id(hdr, bmem->mem.pos); 87642Smax.romanov@nginx.com mmap_msg->size = sb->iobuf[i].iov_len; 87742Smax.romanov@nginx.com 87842Smax.romanov@nginx.com nxt_debug(task, "mmap_msg={%D, %D, %D} to %PI", 87942Smax.romanov@nginx.com mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size, 88042Smax.romanov@nginx.com port->pid); 88142Smax.romanov@nginx.com } 88242Smax.romanov@nginx.com 8831125Smax.romanov@nginx.com sb->iobuf[0].iov_base = mmsg_buf; 88442Smax.romanov@nginx.com sb->iobuf[0].iov_len = bsize; 88542Smax.romanov@nginx.com sb->niov = 1; 88642Smax.romanov@nginx.com sb->size = bsize; 88742Smax.romanov@nginx.com 88842Smax.romanov@nginx.com msg->port_msg.mmap = 1; 88942Smax.romanov@nginx.com } 89042Smax.romanov@nginx.com 89142Smax.romanov@nginx.com 89242Smax.romanov@nginx.com void 893423Smax.romanov@nginx.com nxt_port_mmap_read(nxt_task_t *task, nxt_port_recv_msg_t *msg) 89442Smax.romanov@nginx.com { 89542Smax.romanov@nginx.com nxt_buf_t *b, **pb; 89642Smax.romanov@nginx.com nxt_port_mmap_msg_t *end, *mmap_msg; 89742Smax.romanov@nginx.com 89842Smax.romanov@nginx.com pb = &msg->buf; 89982Smax.romanov@nginx.com msg->size = 0; 90042Smax.romanov@nginx.com 901423Smax.romanov@nginx.com for (b = msg->buf; b != NULL; b = b->next) { 902423Smax.romanov@nginx.com 903423Smax.romanov@nginx.com mmap_msg = (nxt_port_mmap_msg_t *) b->mem.pos; 904423Smax.romanov@nginx.com end = (nxt_port_mmap_msg_t *) b->mem.free; 90542Smax.romanov@nginx.com 906423Smax.romanov@nginx.com while (mmap_msg < end) { 907423Smax.romanov@nginx.com nxt_debug(task, "mmap_msg={%D, %D, %D} from %PI", 908423Smax.romanov@nginx.com mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size, 909423Smax.romanov@nginx.com msg->port_msg.pid); 91042Smax.romanov@nginx.com 911423Smax.romanov@nginx.com *pb = nxt_port_mmap_get_incoming_buf(task, msg->port, 912423Smax.romanov@nginx.com msg->port_msg.pid, mmap_msg); 913423Smax.romanov@nginx.com if (nxt_slow_path(*pb == NULL)) { 914423Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, 915423Smax.romanov@nginx.com "failed to get mmap buffer"); 916423Smax.romanov@nginx.com 917423Smax.romanov@nginx.com break; 918423Smax.romanov@nginx.com } 91942Smax.romanov@nginx.com 920423Smax.romanov@nginx.com msg->size += mmap_msg->size; 921423Smax.romanov@nginx.com pb = &(*pb)->next; 922423Smax.romanov@nginx.com mmap_msg++; 923423Smax.romanov@nginx.com 924423Smax.romanov@nginx.com /* Mark original buf as complete. */ 925423Smax.romanov@nginx.com b->mem.pos += sizeof(nxt_port_mmap_msg_t); 926423Smax.romanov@nginx.com } 92742Smax.romanov@nginx.com } 92842Smax.romanov@nginx.com } 92942Smax.romanov@nginx.com 93042Smax.romanov@nginx.com 93142Smax.romanov@nginx.com nxt_port_method_t 93242Smax.romanov@nginx.com nxt_port_mmap_get_method(nxt_task_t *task, nxt_port_t *port, nxt_buf_t *b) 93342Smax.romanov@nginx.com { 934*1546Smax.romanov@nginx.com nxt_port_method_t m; 93542Smax.romanov@nginx.com 93642Smax.romanov@nginx.com m = NXT_PORT_METHOD_ANY; 93742Smax.romanov@nginx.com 938613Svbart@nginx.com for (/* void */; b != NULL; b = b->next) { 93942Smax.romanov@nginx.com if (nxt_buf_used_size(b) == 0) { 94042Smax.romanov@nginx.com /* empty buffers does not affect method */ 94142Smax.romanov@nginx.com continue; 94242Smax.romanov@nginx.com } 94342Smax.romanov@nginx.com 94442Smax.romanov@nginx.com if (nxt_buf_is_port_mmap(b)) { 94542Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_PLAIN) { 94642Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, 94742Smax.romanov@nginx.com "mixing plain and mmap buffers, " 94842Smax.romanov@nginx.com "using plain mode"); 94942Smax.romanov@nginx.com 95042Smax.romanov@nginx.com break; 95142Smax.romanov@nginx.com } 95242Smax.romanov@nginx.com 95342Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_ANY) { 95442Smax.romanov@nginx.com nxt_debug(task, "using mmap mode"); 95542Smax.romanov@nginx.com 95642Smax.romanov@nginx.com m = NXT_PORT_METHOD_MMAP; 95742Smax.romanov@nginx.com } 95842Smax.romanov@nginx.com } else { 95942Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_MMAP) { 96042Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, 96142Smax.romanov@nginx.com "mixing mmap and plain buffers, " 96242Smax.romanov@nginx.com "switching to plain mode"); 96342Smax.romanov@nginx.com 96442Smax.romanov@nginx.com m = NXT_PORT_METHOD_PLAIN; 96542Smax.romanov@nginx.com 96642Smax.romanov@nginx.com break; 96742Smax.romanov@nginx.com } 96842Smax.romanov@nginx.com 96942Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_ANY) { 97042Smax.romanov@nginx.com nxt_debug(task, "using plain mode"); 97142Smax.romanov@nginx.com 97242Smax.romanov@nginx.com m = NXT_PORT_METHOD_PLAIN; 97342Smax.romanov@nginx.com } 97442Smax.romanov@nginx.com } 97542Smax.romanov@nginx.com } 97642Smax.romanov@nginx.com 97742Smax.romanov@nginx.com return m; 97842Smax.romanov@nginx.com } 979