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