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 19*364Smax.romanov@nginx.com nxt_inline void 2042Smax.romanov@nginx.com nxt_port_mmap_destroy(nxt_port_mmap_t *port_mmap) 2142Smax.romanov@nginx.com { 2280Smax.romanov@nginx.com if (port_mmap->hdr != NULL) { 2380Smax.romanov@nginx.com nxt_mem_munmap(port_mmap->hdr, PORT_MMAP_SIZE); 2480Smax.romanov@nginx.com port_mmap->hdr = NULL; 2542Smax.romanov@nginx.com } 2642Smax.romanov@nginx.com } 2742Smax.romanov@nginx.com 2842Smax.romanov@nginx.com 29*364Smax.romanov@nginx.com static nxt_port_mmap_t * 30*364Smax.romanov@nginx.com nxt_port_mmap_at(nxt_port_mmaps_t *port_mmaps, uint32_t i) 31141Smax.romanov@nginx.com { 32*364Smax.romanov@nginx.com uint32_t cap; 33141Smax.romanov@nginx.com 34*364Smax.romanov@nginx.com cap = port_mmaps->cap; 35141Smax.romanov@nginx.com 36*364Smax.romanov@nginx.com if (cap == 0) { 37*364Smax.romanov@nginx.com cap = i + 1; 38141Smax.romanov@nginx.com } 39141Smax.romanov@nginx.com 40*364Smax.romanov@nginx.com while (i + 1 > cap) { 41*364Smax.romanov@nginx.com 42*364Smax.romanov@nginx.com if (cap < 16) { 43*364Smax.romanov@nginx.com cap = cap * 2; 44141Smax.romanov@nginx.com 45*364Smax.romanov@nginx.com } else { 46*364Smax.romanov@nginx.com cap = cap + cap / 2; 47*364Smax.romanov@nginx.com } 48*364Smax.romanov@nginx.com } 49*364Smax.romanov@nginx.com 50*364Smax.romanov@nginx.com if (cap != port_mmaps->cap) { 51141Smax.romanov@nginx.com 52*364Smax.romanov@nginx.com port_mmaps->elts = nxt_realloc(port_mmaps->elts, 53*364Smax.romanov@nginx.com cap * sizeof(nxt_port_mmap_t)); 54*364Smax.romanov@nginx.com if (nxt_slow_path(port_mmaps->elts == NULL)) { 55*364Smax.romanov@nginx.com return NULL; 56*364Smax.romanov@nginx.com } 57*364Smax.romanov@nginx.com 58*364Smax.romanov@nginx.com nxt_memzero(port_mmaps->elts + port_mmaps->cap, 59*364Smax.romanov@nginx.com sizeof(nxt_port_mmap_t) * (cap - port_mmaps->cap)); 60141Smax.romanov@nginx.com 61*364Smax.romanov@nginx.com port_mmaps->cap = cap; 62*364Smax.romanov@nginx.com } 63*364Smax.romanov@nginx.com 64*364Smax.romanov@nginx.com if (i + 1 > port_mmaps->size) { 65*364Smax.romanov@nginx.com port_mmaps->size = i + 1; 66*364Smax.romanov@nginx.com } 67*364Smax.romanov@nginx.com 68*364Smax.romanov@nginx.com return port_mmaps->elts + i; 69141Smax.romanov@nginx.com } 70141Smax.romanov@nginx.com 71141Smax.romanov@nginx.com 72141Smax.romanov@nginx.com void 73*364Smax.romanov@nginx.com nxt_port_mmaps_destroy(nxt_port_mmaps_t *port_mmaps, nxt_bool_t free) 74141Smax.romanov@nginx.com { 75141Smax.romanov@nginx.com uint32_t i; 76141Smax.romanov@nginx.com nxt_port_mmap_t *port_mmap; 77141Smax.romanov@nginx.com 78141Smax.romanov@nginx.com if (port_mmaps == NULL) { 79141Smax.romanov@nginx.com return; 80141Smax.romanov@nginx.com } 81141Smax.romanov@nginx.com 82141Smax.romanov@nginx.com port_mmap = port_mmaps->elts; 83141Smax.romanov@nginx.com 84*364Smax.romanov@nginx.com for (i = 0; i < port_mmaps->size; i++) { 85*364Smax.romanov@nginx.com nxt_port_mmap_destroy(port_mmap + i); 86141Smax.romanov@nginx.com } 87141Smax.romanov@nginx.com 88*364Smax.romanov@nginx.com port_mmaps->size = 0; 89141Smax.romanov@nginx.com 90*364Smax.romanov@nginx.com if (free != 0) { 91*364Smax.romanov@nginx.com nxt_free(port_mmaps->elts); 92141Smax.romanov@nginx.com } 93141Smax.romanov@nginx.com } 94141Smax.romanov@nginx.com 95141Smax.romanov@nginx.com 96195Smax.romanov@nginx.com #define nxt_port_mmap_free_junk(p, size) \ 97195Smax.romanov@nginx.com memset((p), 0xA5, size) 98195Smax.romanov@nginx.com 99195Smax.romanov@nginx.com 10042Smax.romanov@nginx.com static void 10142Smax.romanov@nginx.com nxt_port_mmap_buf_completion(nxt_task_t *task, void *obj, void *data) 10242Smax.romanov@nginx.com { 10342Smax.romanov@nginx.com u_char *p; 10465Sigor@sysoev.ru nxt_mp_t *mp; 10542Smax.romanov@nginx.com nxt_buf_t *b; 10642Smax.romanov@nginx.com nxt_chunk_id_t c; 10742Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 10842Smax.romanov@nginx.com 109122Smax.romanov@nginx.com if (nxt_buf_ts_handle(task, obj, data)) { 110122Smax.romanov@nginx.com return; 111122Smax.romanov@nginx.com } 112122Smax.romanov@nginx.com 11342Smax.romanov@nginx.com b = obj; 11442Smax.romanov@nginx.com 11542Smax.romanov@nginx.com mp = b->data; 11642Smax.romanov@nginx.com 11779Smax.romanov@nginx.com #if (NXT_DEBUG) 11879Smax.romanov@nginx.com if (nxt_slow_path(data != b->parent)) { 11979Smax.romanov@nginx.com nxt_log_alert(task->log, "completion data (%p) != b->parent (%p)", 12079Smax.romanov@nginx.com data, b->parent); 12179Smax.romanov@nginx.com nxt_abort(); 12279Smax.romanov@nginx.com } 12379Smax.romanov@nginx.com #endif 12479Smax.romanov@nginx.com 12580Smax.romanov@nginx.com hdr = data; 12642Smax.romanov@nginx.com 127363Smax.romanov@nginx.com if (nxt_slow_path(hdr->src_pid != nxt_pid && hdr->dst_pid != nxt_pid)) { 128363Smax.romanov@nginx.com nxt_debug(task, "mmap buf completion: mmap for other process pair " 129363Smax.romanov@nginx.com "%PI->%PI", hdr->src_pid, hdr->dst_pid); 130363Smax.romanov@nginx.com 131363Smax.romanov@nginx.com goto release_buf; 132363Smax.romanov@nginx.com } 133363Smax.romanov@nginx.com 13442Smax.romanov@nginx.com if (b->is_port_mmap_sent && b->mem.pos > b->mem.start) { 13542Smax.romanov@nginx.com /* 13642Smax.romanov@nginx.com * Chunks until b->mem.pos has been sent to other side, 13742Smax.romanov@nginx.com * let's release rest (if any). 13842Smax.romanov@nginx.com */ 13942Smax.romanov@nginx.com p = b->mem.pos - 1; 14080Smax.romanov@nginx.com c = nxt_port_mmap_chunk_id(hdr, p) + 1; 14180Smax.romanov@nginx.com p = nxt_port_mmap_chunk_start(hdr, c); 142141Smax.romanov@nginx.com 14342Smax.romanov@nginx.com } else { 14442Smax.romanov@nginx.com p = b->mem.start; 14580Smax.romanov@nginx.com c = nxt_port_mmap_chunk_id(hdr, p); 14642Smax.romanov@nginx.com } 14742Smax.romanov@nginx.com 148195Smax.romanov@nginx.com nxt_port_mmap_free_junk(p, b->mem.end - p); 149195Smax.romanov@nginx.com 150363Smax.romanov@nginx.com nxt_debug(task, "mmap buf completion: %p [%p,%d] (sent=%d), " 151363Smax.romanov@nginx.com "%PI->%PI,%d,%d", b, b->mem.start, b->mem.end - b->mem.start, 152363Smax.romanov@nginx.com b->is_port_mmap_sent, hdr->src_pid, hdr->dst_pid, hdr->id, c); 153206Smax.romanov@nginx.com 15442Smax.romanov@nginx.com while (p < b->mem.end) { 15542Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(hdr, c); 15642Smax.romanov@nginx.com 15742Smax.romanov@nginx.com p += PORT_MMAP_CHUNK_SIZE; 15842Smax.romanov@nginx.com c++; 15942Smax.romanov@nginx.com } 16042Smax.romanov@nginx.com 161363Smax.romanov@nginx.com release_buf: 162363Smax.romanov@nginx.com 163122Smax.romanov@nginx.com nxt_mp_release(mp, b); 16442Smax.romanov@nginx.com } 16542Smax.romanov@nginx.com 16642Smax.romanov@nginx.com 16780Smax.romanov@nginx.com nxt_port_mmap_header_t * 16842Smax.romanov@nginx.com nxt_port_incoming_port_mmap(nxt_task_t *task, nxt_process_t *process, 16942Smax.romanov@nginx.com nxt_fd_t fd) 17042Smax.romanov@nginx.com { 17180Smax.romanov@nginx.com void *mem; 17280Smax.romanov@nginx.com struct stat mmap_stat; 17380Smax.romanov@nginx.com nxt_port_mmap_t *port_mmap; 17480Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 17542Smax.romanov@nginx.com 17642Smax.romanov@nginx.com nxt_debug(task, "got new mmap fd #%FD from process %PI", 17742Smax.romanov@nginx.com fd, process->pid); 17842Smax.romanov@nginx.com 17980Smax.romanov@nginx.com port_mmap = NULL; 18080Smax.romanov@nginx.com hdr = NULL; 18180Smax.romanov@nginx.com 18242Smax.romanov@nginx.com if (fstat(fd, &mmap_stat) == -1) { 18342Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "fstat(%FD) failed %E", fd, nxt_errno); 18442Smax.romanov@nginx.com 18542Smax.romanov@nginx.com return NULL; 18642Smax.romanov@nginx.com } 18742Smax.romanov@nginx.com 18880Smax.romanov@nginx.com mem = nxt_mem_mmap(NULL, mmap_stat.st_size, 18980Smax.romanov@nginx.com PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 19042Smax.romanov@nginx.com 19180Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 19242Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "mmap() failed %E", nxt_errno); 19342Smax.romanov@nginx.com 194*364Smax.romanov@nginx.com return NULL; 19542Smax.romanov@nginx.com } 19642Smax.romanov@nginx.com 197*364Smax.romanov@nginx.com hdr = mem; 198*364Smax.romanov@nginx.com 199*364Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 20080Smax.romanov@nginx.com 201*364Smax.romanov@nginx.com port_mmap = nxt_port_mmap_at(&process->incoming, hdr->id); 202*364Smax.romanov@nginx.com if (nxt_slow_path(port_mmap == NULL)) { 203*364Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "failed to add mmap to incoming array"); 204*364Smax.romanov@nginx.com 205*364Smax.romanov@nginx.com nxt_mem_munmap(mem, PORT_MMAP_SIZE); 206*364Smax.romanov@nginx.com hdr = NULL; 207*364Smax.romanov@nginx.com 208*364Smax.romanov@nginx.com goto fail; 20980Smax.romanov@nginx.com } 21080Smax.romanov@nginx.com 211363Smax.romanov@nginx.com nxt_assert(hdr->src_pid == process->pid); 212363Smax.romanov@nginx.com nxt_assert(hdr->dst_pid == nxt_pid); 213363Smax.romanov@nginx.com 214*364Smax.romanov@nginx.com port_mmap->hdr = hdr; 215*364Smax.romanov@nginx.com 216323Smax.romanov@nginx.com hdr->sent_over = 0xFFFFu; 217323Smax.romanov@nginx.com 21880Smax.romanov@nginx.com fail: 21980Smax.romanov@nginx.com 220*364Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 22190Smax.romanov@nginx.com 22280Smax.romanov@nginx.com return hdr; 22342Smax.romanov@nginx.com } 22442Smax.romanov@nginx.com 22542Smax.romanov@nginx.com 22680Smax.romanov@nginx.com static nxt_port_mmap_header_t * 22742Smax.romanov@nginx.com nxt_port_new_port_mmap(nxt_task_t *task, nxt_process_t *process, 22842Smax.romanov@nginx.com nxt_port_t *port) 22942Smax.romanov@nginx.com { 23080Smax.romanov@nginx.com void *mem; 23142Smax.romanov@nginx.com u_char *p, name[64]; 23280Smax.romanov@nginx.com nxt_fd_t fd; 23342Smax.romanov@nginx.com nxt_port_mmap_t *port_mmap; 23442Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 23542Smax.romanov@nginx.com 236*364Smax.romanov@nginx.com port_mmap = nxt_port_mmap_at(&process->outgoing, process->outgoing.size); 23742Smax.romanov@nginx.com if (nxt_slow_path(port_mmap == NULL)) { 23842Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, 23942Smax.romanov@nginx.com "failed to add port mmap to outgoing array"); 24042Smax.romanov@nginx.com 24142Smax.romanov@nginx.com return NULL; 24242Smax.romanov@nginx.com } 24342Smax.romanov@nginx.com 244259Sigor@sysoev.ru p = nxt_sprintf(name, name + sizeof(name), "/unit.%PI.%uxD", 245138Sigor@sysoev.ru nxt_pid, nxt_random(&task->thread->random)); 24642Smax.romanov@nginx.com *p = '\0'; 24742Smax.romanov@nginx.com 24842Smax.romanov@nginx.com #if (NXT_HAVE_MEMFD_CREATE) 249277Sigor@sysoev.ru 25080Smax.romanov@nginx.com fd = syscall(SYS_memfd_create, name, MFD_CLOEXEC); 25142Smax.romanov@nginx.com 25280Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 25342Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "memfd_create(%s) failed %E", 25442Smax.romanov@nginx.com name, nxt_errno); 25542Smax.romanov@nginx.com 25642Smax.romanov@nginx.com goto remove_fail; 25742Smax.romanov@nginx.com } 25842Smax.romanov@nginx.com 25980Smax.romanov@nginx.com nxt_debug(task, "memfd_create(%s): %FD", name, fd); 26042Smax.romanov@nginx.com 26142Smax.romanov@nginx.com #elif (NXT_HAVE_SHM_OPEN) 262277Sigor@sysoev.ru 263277Sigor@sysoev.ru /* Just in case. */ 264277Sigor@sysoev.ru shm_unlink((char *) name); 26542Smax.romanov@nginx.com 26680Smax.romanov@nginx.com fd = shm_open((char *) name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); 26742Smax.romanov@nginx.com 26880Smax.romanov@nginx.com nxt_debug(task, "shm_open(%s): %FD", name, fd); 26942Smax.romanov@nginx.com 27080Smax.romanov@nginx.com if (nxt_slow_path(fd == -1)) { 27142Smax.romanov@nginx.com nxt_log(task, NXT_LOG_CRIT, "shm_open(%s) failed %E", name, nxt_errno); 27242Smax.romanov@nginx.com 27342Smax.romanov@nginx.com goto remove_fail; 27442Smax.romanov@nginx.com } 27542Smax.romanov@nginx.com 27642Smax.romanov@nginx.com if (nxt_slow_path(shm_unlink((char *) name) == -1)) { 27742Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "shm_unlink(%s) failed %E", name, 27842Smax.romanov@nginx.com nxt_errno); 27942Smax.romanov@nginx.com } 280277Sigor@sysoev.ru 28142Smax.romanov@nginx.com #endif 28242Smax.romanov@nginx.com 28380Smax.romanov@nginx.com if (nxt_slow_path(ftruncate(fd, PORT_MMAP_SIZE) == -1)) { 28442Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, "ftruncate() failed %E", nxt_errno); 28542Smax.romanov@nginx.com 28642Smax.romanov@nginx.com goto remove_fail; 28742Smax.romanov@nginx.com } 28842Smax.romanov@nginx.com 289277Sigor@sysoev.ru mem = nxt_mem_mmap(NULL, PORT_MMAP_SIZE, PROT_READ | PROT_WRITE, 290277Sigor@sysoev.ru MAP_SHARED, fd, 0); 29142Smax.romanov@nginx.com 29280Smax.romanov@nginx.com if (nxt_slow_path(mem == MAP_FAILED)) { 29342Smax.romanov@nginx.com goto remove_fail; 29442Smax.romanov@nginx.com } 29542Smax.romanov@nginx.com 29680Smax.romanov@nginx.com port_mmap->hdr = mem; 29780Smax.romanov@nginx.com 29842Smax.romanov@nginx.com /* Init segment header. */ 29980Smax.romanov@nginx.com hdr = port_mmap->hdr; 30042Smax.romanov@nginx.com 30142Smax.romanov@nginx.com nxt_memset(hdr->free_map, 0xFFU, sizeof(hdr->free_map)); 30242Smax.romanov@nginx.com 303*364Smax.romanov@nginx.com hdr->id = process->outgoing.size - 1; 304363Smax.romanov@nginx.com hdr->src_pid = nxt_pid; 305363Smax.romanov@nginx.com hdr->dst_pid = process->pid; 306323Smax.romanov@nginx.com hdr->sent_over = port->id; 30780Smax.romanov@nginx.com 30880Smax.romanov@nginx.com /* Mark first chunk as busy */ 30980Smax.romanov@nginx.com nxt_port_mmap_set_chunk_busy(hdr, 0); 31080Smax.romanov@nginx.com 31142Smax.romanov@nginx.com /* Mark as busy chunk followed the last available chunk. */ 31242Smax.romanov@nginx.com nxt_port_mmap_set_chunk_busy(hdr, PORT_MMAP_CHUNK_COUNT); 31342Smax.romanov@nginx.com 314363Smax.romanov@nginx.com nxt_debug(task, "send mmap fd %FD to process %PI", fd, port->pid); 31542Smax.romanov@nginx.com 31642Smax.romanov@nginx.com /* TODO handle error */ 317189Smax.romanov@nginx.com (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_MMAP, fd, 0, 0, NULL); 31842Smax.romanov@nginx.com 31942Smax.romanov@nginx.com nxt_log(task, NXT_LOG_DEBUG, "new mmap #%D created for %PI -> %PI", 32080Smax.romanov@nginx.com hdr->id, nxt_pid, process->pid); 32142Smax.romanov@nginx.com 32280Smax.romanov@nginx.com return hdr; 32342Smax.romanov@nginx.com 32442Smax.romanov@nginx.com remove_fail: 32542Smax.romanov@nginx.com 326*364Smax.romanov@nginx.com process->outgoing.size--; 32742Smax.romanov@nginx.com 32842Smax.romanov@nginx.com return NULL; 32942Smax.romanov@nginx.com } 33042Smax.romanov@nginx.com 33142Smax.romanov@nginx.com 33280Smax.romanov@nginx.com static nxt_port_mmap_header_t * 33342Smax.romanov@nginx.com nxt_port_mmap_get(nxt_task_t *task, nxt_port_t *port, nxt_chunk_id_t *c, 33442Smax.romanov@nginx.com size_t size) 33542Smax.romanov@nginx.com { 33680Smax.romanov@nginx.com nxt_process_t *process; 33780Smax.romanov@nginx.com nxt_port_mmap_t *port_mmap; 33880Smax.romanov@nginx.com nxt_port_mmap_t *end_port_mmap; 33980Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 34042Smax.romanov@nginx.com 34180Smax.romanov@nginx.com process = port->process; 34242Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 34342Smax.romanov@nginx.com return NULL; 34442Smax.romanov@nginx.com } 34542Smax.romanov@nginx.com 34642Smax.romanov@nginx.com *c = 0; 34780Smax.romanov@nginx.com port_mmap = NULL; 34880Smax.romanov@nginx.com hdr = NULL; 34942Smax.romanov@nginx.com 350*364Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->outgoing.mutex); 35180Smax.romanov@nginx.com 352*364Smax.romanov@nginx.com port_mmap = process->outgoing.elts; 353*364Smax.romanov@nginx.com end_port_mmap = port_mmap + process->outgoing.size; 35442Smax.romanov@nginx.com 35542Smax.romanov@nginx.com while (port_mmap < end_port_mmap) { 35642Smax.romanov@nginx.com 357323Smax.romanov@nginx.com if ( (port_mmap->hdr->sent_over == 0xFFFFu || 358323Smax.romanov@nginx.com port_mmap->hdr->sent_over == port->id) && 359323Smax.romanov@nginx.com nxt_port_mmap_get_free_chunk(port_mmap->hdr, c)) { 36080Smax.romanov@nginx.com hdr = port_mmap->hdr; 36180Smax.romanov@nginx.com 36280Smax.romanov@nginx.com goto unlock_return; 36342Smax.romanov@nginx.com } 36442Smax.romanov@nginx.com 36542Smax.romanov@nginx.com port_mmap++; 36642Smax.romanov@nginx.com } 36742Smax.romanov@nginx.com 36842Smax.romanov@nginx.com /* TODO introduce port_mmap limit and release wait. */ 36980Smax.romanov@nginx.com 37080Smax.romanov@nginx.com hdr = nxt_port_new_port_mmap(task, process, port); 37180Smax.romanov@nginx.com 37280Smax.romanov@nginx.com unlock_return: 37380Smax.romanov@nginx.com 374*364Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->outgoing.mutex); 37590Smax.romanov@nginx.com 37680Smax.romanov@nginx.com return hdr; 37742Smax.romanov@nginx.com } 37842Smax.romanov@nginx.com 37942Smax.romanov@nginx.com 38080Smax.romanov@nginx.com static nxt_port_mmap_header_t * 38142Smax.romanov@nginx.com nxt_port_get_port_incoming_mmap(nxt_task_t *task, nxt_pid_t spid, uint32_t id) 38242Smax.romanov@nginx.com { 38380Smax.romanov@nginx.com nxt_process_t *process; 38480Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 38542Smax.romanov@nginx.com 386196Smax.romanov@nginx.com process = nxt_runtime_process_find(task->thread->runtime, spid); 38742Smax.romanov@nginx.com if (nxt_slow_path(process == NULL)) { 38842Smax.romanov@nginx.com return NULL; 38942Smax.romanov@nginx.com } 39042Smax.romanov@nginx.com 39180Smax.romanov@nginx.com hdr = NULL; 39280Smax.romanov@nginx.com 393*364Smax.romanov@nginx.com nxt_thread_mutex_lock(&process->incoming.mutex); 39480Smax.romanov@nginx.com 395*364Smax.romanov@nginx.com if (nxt_fast_path(process->incoming.size > id)) { 396*364Smax.romanov@nginx.com hdr = process->incoming.elts[id].hdr; 397277Sigor@sysoev.ru 39880Smax.romanov@nginx.com } else { 39980Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, 40080Smax.romanov@nginx.com "failed to get incoming mmap #%d for process %PI", id, spid); 40142Smax.romanov@nginx.com } 40242Smax.romanov@nginx.com 403*364Smax.romanov@nginx.com nxt_thread_mutex_unlock(&process->incoming.mutex); 40490Smax.romanov@nginx.com 40580Smax.romanov@nginx.com return hdr; 40642Smax.romanov@nginx.com } 40742Smax.romanov@nginx.com 40842Smax.romanov@nginx.com 40942Smax.romanov@nginx.com nxt_buf_t * 41042Smax.romanov@nginx.com nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_t *port, size_t size) 41142Smax.romanov@nginx.com { 41242Smax.romanov@nginx.com size_t nchunks; 41342Smax.romanov@nginx.com nxt_buf_t *b; 41442Smax.romanov@nginx.com nxt_chunk_id_t c; 41542Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 41642Smax.romanov@nginx.com 41742Smax.romanov@nginx.com nxt_debug(task, "request %z bytes shm buffer", size); 41842Smax.romanov@nginx.com 419342Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, 0); 42042Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 42142Smax.romanov@nginx.com return NULL; 42242Smax.romanov@nginx.com } 42342Smax.romanov@nginx.com 42442Smax.romanov@nginx.com b->completion_handler = nxt_port_mmap_buf_completion; 42542Smax.romanov@nginx.com nxt_buf_set_port_mmap(b); 42642Smax.romanov@nginx.com 42780Smax.romanov@nginx.com hdr = nxt_port_mmap_get(task, port, &c, size); 42880Smax.romanov@nginx.com if (nxt_slow_path(hdr == NULL)) { 429342Smax.romanov@nginx.com nxt_mp_release(task->thread->engine->mem_pool, b); 43042Smax.romanov@nginx.com return NULL; 43142Smax.romanov@nginx.com } 43242Smax.romanov@nginx.com 43380Smax.romanov@nginx.com b->parent = hdr; 434122Smax.romanov@nginx.com 43580Smax.romanov@nginx.com b->mem.start = nxt_port_mmap_chunk_start(hdr, c); 43642Smax.romanov@nginx.com b->mem.pos = b->mem.start; 43742Smax.romanov@nginx.com b->mem.free = b->mem.start; 43842Smax.romanov@nginx.com b->mem.end = b->mem.start + PORT_MMAP_CHUNK_SIZE; 43942Smax.romanov@nginx.com 44042Smax.romanov@nginx.com nchunks = size / PORT_MMAP_CHUNK_SIZE; 44142Smax.romanov@nginx.com if ((size % PORT_MMAP_CHUNK_SIZE) != 0 || nchunks == 0) { 44242Smax.romanov@nginx.com nchunks++; 44342Smax.romanov@nginx.com } 44442Smax.romanov@nginx.com 445363Smax.romanov@nginx.com nxt_debug(task, "outgoing mmap buf allocation: %p [%p,%d] %PI->%PI,%d,%d", 446363Smax.romanov@nginx.com b, b->mem.start, b->mem.end - b->mem.start, 447363Smax.romanov@nginx.com hdr->src_pid, hdr->dst_pid, hdr->id, c); 448206Smax.romanov@nginx.com 44942Smax.romanov@nginx.com c++; 45042Smax.romanov@nginx.com nchunks--; 45142Smax.romanov@nginx.com 45242Smax.romanov@nginx.com /* Try to acquire as much chunks as required. */ 45342Smax.romanov@nginx.com while (nchunks > 0) { 45442Smax.romanov@nginx.com 45580Smax.romanov@nginx.com if (nxt_port_mmap_chk_set_chunk_busy(hdr, c) == 0) { 45642Smax.romanov@nginx.com break; 45742Smax.romanov@nginx.com } 45842Smax.romanov@nginx.com 45942Smax.romanov@nginx.com b->mem.end += PORT_MMAP_CHUNK_SIZE; 46042Smax.romanov@nginx.com c++; 46142Smax.romanov@nginx.com nchunks--; 46242Smax.romanov@nginx.com } 46342Smax.romanov@nginx.com 46442Smax.romanov@nginx.com return b; 46542Smax.romanov@nginx.com } 46642Smax.romanov@nginx.com 46742Smax.romanov@nginx.com 46880Smax.romanov@nginx.com nxt_int_t 469206Smax.romanov@nginx.com nxt_port_mmap_increase_buf(nxt_task_t *task, nxt_buf_t *b, size_t size, 470206Smax.romanov@nginx.com size_t min_size) 47180Smax.romanov@nginx.com { 472206Smax.romanov@nginx.com size_t nchunks, free_size; 47380Smax.romanov@nginx.com nxt_chunk_id_t c, start; 47480Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 47580Smax.romanov@nginx.com 47680Smax.romanov@nginx.com nxt_debug(task, "request increase %z bytes shm buffer", size); 47780Smax.romanov@nginx.com 47880Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_is_port_mmap(b) == 0)) { 47980Smax.romanov@nginx.com nxt_log(task, NXT_LOG_WARN, 48080Smax.romanov@nginx.com "failed to increase, not a mmap buffer"); 48180Smax.romanov@nginx.com return NXT_ERROR; 48280Smax.romanov@nginx.com } 48380Smax.romanov@nginx.com 484206Smax.romanov@nginx.com free_size = nxt_buf_mem_free_size(&b->mem); 485206Smax.romanov@nginx.com 486206Smax.romanov@nginx.com if (nxt_slow_path(size <= free_size)) { 48780Smax.romanov@nginx.com return NXT_OK; 48880Smax.romanov@nginx.com } 48980Smax.romanov@nginx.com 49080Smax.romanov@nginx.com hdr = b->parent; 49180Smax.romanov@nginx.com 49280Smax.romanov@nginx.com start = nxt_port_mmap_chunk_id(hdr, b->mem.end); 49380Smax.romanov@nginx.com 494206Smax.romanov@nginx.com size -= free_size; 49580Smax.romanov@nginx.com 49680Smax.romanov@nginx.com nchunks = size / PORT_MMAP_CHUNK_SIZE; 49780Smax.romanov@nginx.com if ((size % PORT_MMAP_CHUNK_SIZE) != 0 || nchunks == 0) { 49880Smax.romanov@nginx.com nchunks++; 49980Smax.romanov@nginx.com } 50080Smax.romanov@nginx.com 50180Smax.romanov@nginx.com c = start; 50280Smax.romanov@nginx.com 50380Smax.romanov@nginx.com /* Try to acquire as much chunks as required. */ 50480Smax.romanov@nginx.com while (nchunks > 0) { 50580Smax.romanov@nginx.com 50680Smax.romanov@nginx.com if (nxt_port_mmap_chk_set_chunk_busy(hdr, c) == 0) { 50780Smax.romanov@nginx.com break; 50880Smax.romanov@nginx.com } 50980Smax.romanov@nginx.com 51080Smax.romanov@nginx.com c++; 51180Smax.romanov@nginx.com nchunks--; 51280Smax.romanov@nginx.com } 51380Smax.romanov@nginx.com 514277Sigor@sysoev.ru if (nchunks != 0 515277Sigor@sysoev.ru && min_size > free_size + PORT_MMAP_CHUNK_SIZE * (c - start)) 516277Sigor@sysoev.ru { 51780Smax.romanov@nginx.com c--; 51880Smax.romanov@nginx.com while (c >= start) { 51980Smax.romanov@nginx.com nxt_port_mmap_set_chunk_free(hdr, c); 52080Smax.romanov@nginx.com c--; 52180Smax.romanov@nginx.com } 52280Smax.romanov@nginx.com 52380Smax.romanov@nginx.com nxt_debug(task, "failed to increase, %d chunks busy", nchunks); 52480Smax.romanov@nginx.com 52580Smax.romanov@nginx.com return NXT_ERROR; 526277Sigor@sysoev.ru 52780Smax.romanov@nginx.com } else { 52880Smax.romanov@nginx.com b->mem.end += PORT_MMAP_CHUNK_SIZE * (c - start); 52980Smax.romanov@nginx.com 53080Smax.romanov@nginx.com return NXT_OK; 53180Smax.romanov@nginx.com } 53280Smax.romanov@nginx.com } 53380Smax.romanov@nginx.com 53480Smax.romanov@nginx.com 53542Smax.romanov@nginx.com static nxt_buf_t * 53642Smax.romanov@nginx.com nxt_port_mmap_get_incoming_buf(nxt_task_t *task, nxt_port_t *port, 53742Smax.romanov@nginx.com nxt_pid_t spid, nxt_port_mmap_msg_t *mmap_msg) 53842Smax.romanov@nginx.com { 53942Smax.romanov@nginx.com size_t nchunks; 54042Smax.romanov@nginx.com nxt_buf_t *b; 54180Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 54280Smax.romanov@nginx.com 54380Smax.romanov@nginx.com hdr = nxt_port_get_port_incoming_mmap(task, spid, mmap_msg->mmap_id); 54480Smax.romanov@nginx.com if (nxt_slow_path(hdr == NULL)) { 54580Smax.romanov@nginx.com return NULL; 54680Smax.romanov@nginx.com } 54742Smax.romanov@nginx.com 548122Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, port->mem_pool, 0); 54942Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 55042Smax.romanov@nginx.com return NULL; 55142Smax.romanov@nginx.com } 55242Smax.romanov@nginx.com 55342Smax.romanov@nginx.com b->completion_handler = nxt_port_mmap_buf_completion; 55442Smax.romanov@nginx.com 55542Smax.romanov@nginx.com nxt_buf_set_port_mmap(b); 55642Smax.romanov@nginx.com 55742Smax.romanov@nginx.com nchunks = mmap_msg->size / PORT_MMAP_CHUNK_SIZE; 55842Smax.romanov@nginx.com if ((mmap_msg->size % PORT_MMAP_CHUNK_SIZE) != 0) { 55942Smax.romanov@nginx.com nchunks++; 56042Smax.romanov@nginx.com } 56142Smax.romanov@nginx.com 56280Smax.romanov@nginx.com b->mem.start = nxt_port_mmap_chunk_start(hdr, mmap_msg->chunk_id); 56342Smax.romanov@nginx.com b->mem.pos = b->mem.start; 56442Smax.romanov@nginx.com b->mem.free = b->mem.start + mmap_msg->size; 56542Smax.romanov@nginx.com b->mem.end = b->mem.start + nchunks * PORT_MMAP_CHUNK_SIZE; 56642Smax.romanov@nginx.com 56780Smax.romanov@nginx.com b->parent = hdr; 56842Smax.romanov@nginx.com 569363Smax.romanov@nginx.com nxt_debug(task, "incoming mmap buf allocation: %p [%p,%d] %PI->%PI,%d,%d", 570277Sigor@sysoev.ru b, b->mem.start, b->mem.end - b->mem.start, 571363Smax.romanov@nginx.com hdr->src_pid, hdr->dst_pid, hdr->id, mmap_msg->chunk_id); 572206Smax.romanov@nginx.com 57342Smax.romanov@nginx.com return b; 57442Smax.romanov@nginx.com } 57542Smax.romanov@nginx.com 57642Smax.romanov@nginx.com 57742Smax.romanov@nginx.com void 57842Smax.romanov@nginx.com nxt_port_mmap_write(nxt_task_t *task, nxt_port_t *port, 57942Smax.romanov@nginx.com nxt_port_send_msg_t *msg, nxt_sendbuf_coalesce_t *sb) 58042Smax.romanov@nginx.com { 58180Smax.romanov@nginx.com size_t bsize; 582197Smax.romanov@nginx.com nxt_buf_t *bmem; 58380Smax.romanov@nginx.com nxt_uint_t i; 58480Smax.romanov@nginx.com nxt_port_mmap_msg_t *mmap_msg; 58580Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 58642Smax.romanov@nginx.com 58742Smax.romanov@nginx.com nxt_debug(task, "prepare %z bytes message for transfer to process %PI " 588277Sigor@sysoev.ru "via shared memory", sb->size, port->pid); 58942Smax.romanov@nginx.com 59042Smax.romanov@nginx.com bsize = sb->niov * sizeof(nxt_port_mmap_msg_t); 591197Smax.romanov@nginx.com mmap_msg = port->mmsg_buf; 59242Smax.romanov@nginx.com 59342Smax.romanov@nginx.com bmem = msg->buf; 59442Smax.romanov@nginx.com 59542Smax.romanov@nginx.com for (i = 0; i < sb->niov; i++, mmap_msg++) { 59642Smax.romanov@nginx.com 59742Smax.romanov@nginx.com /* Lookup buffer which starts current iov_base. */ 59842Smax.romanov@nginx.com while (bmem && sb->iobuf[i].iov_base != bmem->mem.pos) { 59942Smax.romanov@nginx.com bmem = bmem->next; 60042Smax.romanov@nginx.com } 60142Smax.romanov@nginx.com 60242Smax.romanov@nginx.com if (nxt_slow_path(bmem == NULL)) { 603277Sigor@sysoev.ru nxt_log_error(NXT_LOG_ERR, task->log, 604277Sigor@sysoev.ru "failed to find buf for iobuf[%d]", i); 60542Smax.romanov@nginx.com return; 60642Smax.romanov@nginx.com /* TODO clear b and exit */ 60742Smax.romanov@nginx.com } 60842Smax.romanov@nginx.com 60980Smax.romanov@nginx.com hdr = bmem->parent; 61042Smax.romanov@nginx.com 61180Smax.romanov@nginx.com mmap_msg->mmap_id = hdr->id; 61280Smax.romanov@nginx.com mmap_msg->chunk_id = nxt_port_mmap_chunk_id(hdr, bmem->mem.pos); 61342Smax.romanov@nginx.com mmap_msg->size = sb->iobuf[i].iov_len; 61442Smax.romanov@nginx.com 61542Smax.romanov@nginx.com nxt_debug(task, "mmap_msg={%D, %D, %D} to %PI", 61642Smax.romanov@nginx.com mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size, 61742Smax.romanov@nginx.com port->pid); 61842Smax.romanov@nginx.com } 61942Smax.romanov@nginx.com 620197Smax.romanov@nginx.com sb->iobuf[0].iov_base = port->mmsg_buf; 62142Smax.romanov@nginx.com sb->iobuf[0].iov_len = bsize; 62242Smax.romanov@nginx.com sb->niov = 1; 62342Smax.romanov@nginx.com sb->size = bsize; 62442Smax.romanov@nginx.com 62542Smax.romanov@nginx.com msg->port_msg.mmap = 1; 62642Smax.romanov@nginx.com } 62742Smax.romanov@nginx.com 62842Smax.romanov@nginx.com 62942Smax.romanov@nginx.com void 63042Smax.romanov@nginx.com nxt_port_mmap_read(nxt_task_t *task, nxt_port_t *port, 63182Smax.romanov@nginx.com nxt_port_recv_msg_t *msg) 63242Smax.romanov@nginx.com { 63342Smax.romanov@nginx.com nxt_buf_t *b, **pb; 63442Smax.romanov@nginx.com nxt_port_mmap_msg_t *end, *mmap_msg; 63542Smax.romanov@nginx.com 63642Smax.romanov@nginx.com b = msg->buf; 63742Smax.romanov@nginx.com 63842Smax.romanov@nginx.com mmap_msg = (nxt_port_mmap_msg_t *) b->mem.pos; 63942Smax.romanov@nginx.com end = (nxt_port_mmap_msg_t *) b->mem.free; 64042Smax.romanov@nginx.com 64142Smax.romanov@nginx.com pb = &msg->buf; 64282Smax.romanov@nginx.com msg->size = 0; 64342Smax.romanov@nginx.com 64442Smax.romanov@nginx.com while (mmap_msg < end) { 64542Smax.romanov@nginx.com nxt_debug(task, "mmap_msg={%D, %D, %D} from %PI", 64642Smax.romanov@nginx.com mmap_msg->mmap_id, mmap_msg->chunk_id, mmap_msg->size, 64742Smax.romanov@nginx.com msg->port_msg.pid); 64842Smax.romanov@nginx.com 64942Smax.romanov@nginx.com *pb = nxt_port_mmap_get_incoming_buf(task, port, msg->port_msg.pid, 65042Smax.romanov@nginx.com mmap_msg); 65142Smax.romanov@nginx.com if (nxt_slow_path(*pb == NULL)) { 65242Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, "failed to get mmap buffer"); 65342Smax.romanov@nginx.com 65442Smax.romanov@nginx.com break; 65542Smax.romanov@nginx.com } 65642Smax.romanov@nginx.com 65782Smax.romanov@nginx.com msg->size += mmap_msg->size; 65842Smax.romanov@nginx.com pb = &(*pb)->next; 65942Smax.romanov@nginx.com mmap_msg++; 66042Smax.romanov@nginx.com } 66142Smax.romanov@nginx.com 66242Smax.romanov@nginx.com /* Mark original buf as complete. */ 66342Smax.romanov@nginx.com b->mem.pos += nxt_buf_used_size(b); 66442Smax.romanov@nginx.com } 66542Smax.romanov@nginx.com 66642Smax.romanov@nginx.com 66742Smax.romanov@nginx.com nxt_port_method_t 66842Smax.romanov@nginx.com nxt_port_mmap_get_method(nxt_task_t *task, nxt_port_t *port, nxt_buf_t *b) 66942Smax.romanov@nginx.com { 67080Smax.romanov@nginx.com nxt_port_method_t m; 67180Smax.romanov@nginx.com nxt_port_mmap_header_t *hdr; 67242Smax.romanov@nginx.com 67342Smax.romanov@nginx.com m = NXT_PORT_METHOD_ANY; 67442Smax.romanov@nginx.com 67542Smax.romanov@nginx.com for (; b != NULL; b = b->next) { 67642Smax.romanov@nginx.com if (nxt_buf_used_size(b) == 0) { 67742Smax.romanov@nginx.com /* empty buffers does not affect method */ 67842Smax.romanov@nginx.com continue; 67942Smax.romanov@nginx.com } 68042Smax.romanov@nginx.com 68142Smax.romanov@nginx.com if (nxt_buf_is_port_mmap(b)) { 68280Smax.romanov@nginx.com hdr = b->parent; 68342Smax.romanov@nginx.com 68442Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_PLAIN) { 68542Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, 68642Smax.romanov@nginx.com "mixing plain and mmap buffers, " 68742Smax.romanov@nginx.com "using plain mode"); 68842Smax.romanov@nginx.com 68942Smax.romanov@nginx.com break; 69042Smax.romanov@nginx.com } 69142Smax.romanov@nginx.com 692363Smax.romanov@nginx.com if (port->pid != hdr->dst_pid) { 69342Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, 69442Smax.romanov@nginx.com "send mmap buffer for %PI to %PI, " 695363Smax.romanov@nginx.com "using plain mode", hdr->dst_pid, port->pid); 69642Smax.romanov@nginx.com 69742Smax.romanov@nginx.com m = NXT_PORT_METHOD_PLAIN; 69842Smax.romanov@nginx.com 69942Smax.romanov@nginx.com break; 70042Smax.romanov@nginx.com } 70142Smax.romanov@nginx.com 70242Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_ANY) { 70342Smax.romanov@nginx.com nxt_debug(task, "using mmap mode"); 70442Smax.romanov@nginx.com 70542Smax.romanov@nginx.com m = NXT_PORT_METHOD_MMAP; 70642Smax.romanov@nginx.com } 70742Smax.romanov@nginx.com } else { 70842Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_MMAP) { 70942Smax.romanov@nginx.com nxt_log_error(NXT_LOG_ERR, task->log, 71042Smax.romanov@nginx.com "mixing mmap and plain buffers, " 71142Smax.romanov@nginx.com "switching to plain mode"); 71242Smax.romanov@nginx.com 71342Smax.romanov@nginx.com m = NXT_PORT_METHOD_PLAIN; 71442Smax.romanov@nginx.com 71542Smax.romanov@nginx.com break; 71642Smax.romanov@nginx.com } 71742Smax.romanov@nginx.com 71842Smax.romanov@nginx.com if (m == NXT_PORT_METHOD_ANY) { 71942Smax.romanov@nginx.com nxt_debug(task, "using plain mode"); 72042Smax.romanov@nginx.com 72142Smax.romanov@nginx.com m = NXT_PORT_METHOD_PLAIN; 72242Smax.romanov@nginx.com } 72342Smax.romanov@nginx.com } 72442Smax.romanov@nginx.com } 72542Smax.romanov@nginx.com 72642Smax.romanov@nginx.com return m; 72742Smax.romanov@nginx.com } 728