10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 101Sigor@sysoev.ru static void nxt_buf_completion(nxt_task_t *task, void *obj, void *data); 11122Smax.romanov@nginx.com static void nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data); 12122Smax.romanov@nginx.com 13122Smax.romanov@nginx.com 14122Smax.romanov@nginx.com typedef struct { 15122Smax.romanov@nginx.com nxt_work_t work; 16122Smax.romanov@nginx.com nxt_event_engine_t *engine; 17122Smax.romanov@nginx.com } nxt_buf_ts_t; 180Sigor@sysoev.ru 190Sigor@sysoev.ru 204Sigor@sysoev.ru void 214Sigor@sysoev.ru nxt_buf_mem_init(nxt_buf_t *b, void *start, size_t size) 224Sigor@sysoev.ru { 234Sigor@sysoev.ru b->mem.start = start; 244Sigor@sysoev.ru b->mem.pos = start; 254Sigor@sysoev.ru b->mem.free = start; 2698Svbart@nginx.com b->mem.end = nxt_pointer_to(start, size); 274Sigor@sysoev.ru } 284Sigor@sysoev.ru 294Sigor@sysoev.ru 300Sigor@sysoev.ru nxt_buf_t * 3165Sigor@sysoev.ru nxt_buf_mem_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags) 320Sigor@sysoev.ru { 330Sigor@sysoev.ru nxt_buf_t *b; 340Sigor@sysoev.ru 35122Smax.romanov@nginx.com b = nxt_mp_alloc(mp, NXT_BUF_MEM_SIZE + size); 360Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 370Sigor@sysoev.ru return NULL; 380Sigor@sysoev.ru } 390Sigor@sysoev.ru 40122Smax.romanov@nginx.com nxt_memzero(b, NXT_BUF_MEM_SIZE); 41122Smax.romanov@nginx.com 420Sigor@sysoev.ru b->data = mp; 430Sigor@sysoev.ru b->completion_handler = nxt_buf_completion; 440Sigor@sysoev.ru 450Sigor@sysoev.ru if (size != 0) { 46122Smax.romanov@nginx.com b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); 470Sigor@sysoev.ru b->mem.pos = b->mem.start; 480Sigor@sysoev.ru b->mem.free = b->mem.start; 490Sigor@sysoev.ru b->mem.end = b->mem.start + size; 500Sigor@sysoev.ru } 510Sigor@sysoev.ru 520Sigor@sysoev.ru return b; 530Sigor@sysoev.ru } 540Sigor@sysoev.ru 550Sigor@sysoev.ru 560Sigor@sysoev.ru nxt_buf_t * 57122Smax.romanov@nginx.com nxt_buf_mem_ts_alloc(nxt_task_t *task, nxt_mp_t *mp, size_t size) 580Sigor@sysoev.ru { 59122Smax.romanov@nginx.com nxt_buf_t *b; 60122Smax.romanov@nginx.com nxt_buf_ts_t *ts; 610Sigor@sysoev.ru 62122Smax.romanov@nginx.com b = nxt_mp_retain(mp, NXT_BUF_MEM_SIZE + sizeof(nxt_buf_ts_t) + size); 630Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 640Sigor@sysoev.ru return NULL; 650Sigor@sysoev.ru } 660Sigor@sysoev.ru 67122Smax.romanov@nginx.com nxt_memzero(b, NXT_BUF_MEM_SIZE + sizeof(nxt_buf_ts_t)); 68122Smax.romanov@nginx.com 69122Smax.romanov@nginx.com b->data = mp; 70122Smax.romanov@nginx.com b->completion_handler = nxt_buf_ts_completion; 71122Smax.romanov@nginx.com b->is_ts = 1; 72122Smax.romanov@nginx.com 73122Smax.romanov@nginx.com if (size != 0) { 74122Smax.romanov@nginx.com b->mem.start = nxt_pointer_to(b, NXT_BUF_MEM_SIZE + 75122Smax.romanov@nginx.com sizeof(nxt_buf_ts_t)); 76122Smax.romanov@nginx.com b->mem.pos = b->mem.start; 77122Smax.romanov@nginx.com b->mem.free = b->mem.start; 78122Smax.romanov@nginx.com b->mem.end = b->mem.start + size; 79122Smax.romanov@nginx.com } 80122Smax.romanov@nginx.com 81122Smax.romanov@nginx.com ts = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); 82122Smax.romanov@nginx.com ts->engine = task->thread->engine; 83122Smax.romanov@nginx.com 84122Smax.romanov@nginx.com ts->work.handler = nxt_buf_ts_completion; 85122Smax.romanov@nginx.com ts->work.task = task; 86122Smax.romanov@nginx.com ts->work.obj = b; 87122Smax.romanov@nginx.com ts->work.data = b->parent; 88122Smax.romanov@nginx.com 89122Smax.romanov@nginx.com return b; 90122Smax.romanov@nginx.com } 91122Smax.romanov@nginx.com 92122Smax.romanov@nginx.com 93122Smax.romanov@nginx.com nxt_buf_t * 94122Smax.romanov@nginx.com nxt_buf_file_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags) 95122Smax.romanov@nginx.com { 96122Smax.romanov@nginx.com nxt_buf_t *b; 97122Smax.romanov@nginx.com 98122Smax.romanov@nginx.com b = nxt_mp_alloc(mp, NXT_BUF_FILE_SIZE + size); 99122Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 100122Smax.romanov@nginx.com return NULL; 101122Smax.romanov@nginx.com } 102122Smax.romanov@nginx.com 103122Smax.romanov@nginx.com nxt_memzero(b, NXT_BUF_FILE_SIZE); 104122Smax.romanov@nginx.com 1050Sigor@sysoev.ru b->data = mp; 1060Sigor@sysoev.ru b->completion_handler = nxt_buf_completion; 1070Sigor@sysoev.ru nxt_buf_set_file(b); 1080Sigor@sysoev.ru 1090Sigor@sysoev.ru if (size != 0) { 110122Smax.romanov@nginx.com b->mem.start = nxt_pointer_to(b, NXT_BUF_FILE_SIZE); 1110Sigor@sysoev.ru b->mem.pos = b->mem.start; 1120Sigor@sysoev.ru b->mem.free = b->mem.start; 1130Sigor@sysoev.ru b->mem.end = b->mem.start + size; 1140Sigor@sysoev.ru } 1150Sigor@sysoev.ru 1160Sigor@sysoev.ru return b; 1170Sigor@sysoev.ru } 1180Sigor@sysoev.ru 1190Sigor@sysoev.ru 1200Sigor@sysoev.ru nxt_buf_t * 12165Sigor@sysoev.ru nxt_buf_mmap_alloc(nxt_mp_t *mp, size_t size) 1220Sigor@sysoev.ru { 1230Sigor@sysoev.ru nxt_buf_t *b; 1240Sigor@sysoev.ru 12565Sigor@sysoev.ru b = nxt_mp_zalloc(mp, NXT_BUF_MMAP_SIZE); 1260Sigor@sysoev.ru 1270Sigor@sysoev.ru if (nxt_fast_path(b != NULL)) { 1280Sigor@sysoev.ru b->data = mp; 1290Sigor@sysoev.ru b->completion_handler = nxt_buf_completion; 1300Sigor@sysoev.ru 1310Sigor@sysoev.ru nxt_buf_set_file(b); 1320Sigor@sysoev.ru nxt_buf_set_mmap(b); 1330Sigor@sysoev.ru nxt_buf_mem_set_size(&b->mem, size); 1340Sigor@sysoev.ru } 1350Sigor@sysoev.ru 1360Sigor@sysoev.ru return b; 1370Sigor@sysoev.ru } 1380Sigor@sysoev.ru 1390Sigor@sysoev.ru 1400Sigor@sysoev.ru nxt_buf_t * 14165Sigor@sysoev.ru nxt_buf_sync_alloc(nxt_mp_t *mp, nxt_uint_t flags) 1420Sigor@sysoev.ru { 1430Sigor@sysoev.ru nxt_buf_t *b; 1440Sigor@sysoev.ru 14565Sigor@sysoev.ru b = nxt_mp_zalloc(mp, NXT_BUF_SYNC_SIZE); 1460Sigor@sysoev.ru 1470Sigor@sysoev.ru if (nxt_fast_path(b != NULL)) { 1480Sigor@sysoev.ru b->data = mp; 1490Sigor@sysoev.ru b->completion_handler = nxt_buf_completion; 1500Sigor@sysoev.ru 1510Sigor@sysoev.ru nxt_buf_set_sync(b); 1520Sigor@sysoev.ru b->is_nobuf = ((flags & NXT_BUF_SYNC_NOBUF) != 0); 1530Sigor@sysoev.ru b->is_flush = ((flags & NXT_BUF_SYNC_FLUSH) != 0); 1540Sigor@sysoev.ru b->is_last = ((flags & NXT_BUF_SYNC_LAST) != 0); 1550Sigor@sysoev.ru } 1560Sigor@sysoev.ru 1570Sigor@sysoev.ru return b; 1580Sigor@sysoev.ru } 1590Sigor@sysoev.ru 1600Sigor@sysoev.ru 1610Sigor@sysoev.ru void 1620Sigor@sysoev.ru nxt_buf_chain_add(nxt_buf_t **head, nxt_buf_t *in) 1630Sigor@sysoev.ru { 1640Sigor@sysoev.ru nxt_buf_t *b, **prev; 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru prev = head; 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru for (b = *head; b != NULL; b = b->next) { 1690Sigor@sysoev.ru prev = &b->next; 1700Sigor@sysoev.ru } 1710Sigor@sysoev.ru 1720Sigor@sysoev.ru *prev = in; 1730Sigor@sysoev.ru } 1740Sigor@sysoev.ru 1750Sigor@sysoev.ru 1760Sigor@sysoev.ru size_t 1770Sigor@sysoev.ru nxt_buf_chain_length(nxt_buf_t *b) 1780Sigor@sysoev.ru { 1790Sigor@sysoev.ru size_t length; 1800Sigor@sysoev.ru 1810Sigor@sysoev.ru length = 0; 1820Sigor@sysoev.ru 1830Sigor@sysoev.ru while (b != NULL) { 1840Sigor@sysoev.ru length += b->mem.free - b->mem.pos; 1850Sigor@sysoev.ru b = b->next; 1860Sigor@sysoev.ru } 1870Sigor@sysoev.ru 1880Sigor@sysoev.ru return length; 1890Sigor@sysoev.ru } 1900Sigor@sysoev.ru 1910Sigor@sysoev.ru 1920Sigor@sysoev.ru static void 1931Sigor@sysoev.ru nxt_buf_completion(nxt_task_t *task, void *obj, void *data) 1940Sigor@sysoev.ru { 19565Sigor@sysoev.ru nxt_mp_t *mp; 19665Sigor@sysoev.ru nxt_buf_t *b, *parent; 1970Sigor@sysoev.ru 1980Sigor@sysoev.ru b = obj; 1990Sigor@sysoev.ru parent = data; 2000Sigor@sysoev.ru 2011Sigor@sysoev.ru nxt_debug(task, "buf completion: %p %p", b, b->mem.start); 2020Sigor@sysoev.ru 203122Smax.romanov@nginx.com #if (NXT_DEBUG) 204122Smax.romanov@nginx.com if (nxt_slow_path(data != b->parent)) { 205122Smax.romanov@nginx.com nxt_log_alert(task->log, "completion data (%p) != b->parent (%p)", 206122Smax.romanov@nginx.com data, b->parent); 207122Smax.romanov@nginx.com nxt_abort(); 208122Smax.romanov@nginx.com } 209122Smax.romanov@nginx.com #endif 210122Smax.romanov@nginx.com 2110Sigor@sysoev.ru mp = b->data; 212122Smax.romanov@nginx.com nxt_mp_free(mp, b); 2130Sigor@sysoev.ru 2140Sigor@sysoev.ru if (parent != NULL) { 2151Sigor@sysoev.ru nxt_debug(task, "parent retain:%uD", parent->retain); 2160Sigor@sysoev.ru 2170Sigor@sysoev.ru parent->retain--; 2180Sigor@sysoev.ru 2190Sigor@sysoev.ru if (parent->retain == 0) { 2200Sigor@sysoev.ru parent->mem.pos = parent->mem.free; 2210Sigor@sysoev.ru 2221Sigor@sysoev.ru parent->completion_handler(task, parent, parent->parent); 2230Sigor@sysoev.ru } 2240Sigor@sysoev.ru } 2250Sigor@sysoev.ru } 226122Smax.romanov@nginx.com 227122Smax.romanov@nginx.com 228122Smax.romanov@nginx.com nxt_int_t 229122Smax.romanov@nginx.com nxt_buf_ts_handle(nxt_task_t *task, void *obj, void *data) 230122Smax.romanov@nginx.com { 231122Smax.romanov@nginx.com nxt_buf_t *b; 232122Smax.romanov@nginx.com nxt_buf_ts_t *ts; 233122Smax.romanov@nginx.com 234122Smax.romanov@nginx.com b = obj; 235122Smax.romanov@nginx.com 236122Smax.romanov@nginx.com #if (NXT_DEBUG) 237122Smax.romanov@nginx.com if (nxt_slow_path(b->is_ts == 0)) { 238122Smax.romanov@nginx.com nxt_log_alert(task->log, "not a thread safe buf (%p) completed", b); 239122Smax.romanov@nginx.com nxt_abort(); 240122Smax.romanov@nginx.com } 241122Smax.romanov@nginx.com #endif 242122Smax.romanov@nginx.com 243122Smax.romanov@nginx.com ts = nxt_pointer_to(b, NXT_BUF_MEM_SIZE); 244122Smax.romanov@nginx.com 245122Smax.romanov@nginx.com if (ts->engine != task->thread->engine) { 246122Smax.romanov@nginx.com 247122Smax.romanov@nginx.com nxt_debug(task, "buf ts: %p current engine is %p, expected %p", 248122Smax.romanov@nginx.com b, task->thread->engine, ts->engine); 249122Smax.romanov@nginx.com 250122Smax.romanov@nginx.com ts->work.handler = b->completion_handler; 251122Smax.romanov@nginx.com ts->work.obj = obj; 252122Smax.romanov@nginx.com ts->work.data = data; 253122Smax.romanov@nginx.com 254122Smax.romanov@nginx.com nxt_event_engine_post(ts->engine, &ts->work); 255122Smax.romanov@nginx.com 256122Smax.romanov@nginx.com return 1; 257122Smax.romanov@nginx.com } 258122Smax.romanov@nginx.com 259122Smax.romanov@nginx.com return 0; 260122Smax.romanov@nginx.com } 261122Smax.romanov@nginx.com 262122Smax.romanov@nginx.com 263122Smax.romanov@nginx.com static void 264122Smax.romanov@nginx.com nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data) 265122Smax.romanov@nginx.com { 266122Smax.romanov@nginx.com nxt_mp_t *mp; 267122Smax.romanov@nginx.com nxt_buf_t *b, *parent; 268122Smax.romanov@nginx.com 269122Smax.romanov@nginx.com b = obj; 270122Smax.romanov@nginx.com parent = data; 271122Smax.romanov@nginx.com 272122Smax.romanov@nginx.com if (nxt_buf_ts_handle(task, obj, data)) { 273122Smax.romanov@nginx.com return; 274122Smax.romanov@nginx.com } 275122Smax.romanov@nginx.com 276122Smax.romanov@nginx.com nxt_debug(task, "buf ts completion: %p %p", b, b->mem.start); 277122Smax.romanov@nginx.com 278122Smax.romanov@nginx.com #if (NXT_DEBUG) 279122Smax.romanov@nginx.com if (nxt_slow_path(data != b->parent)) { 280122Smax.romanov@nginx.com nxt_log_alert(task->log, "completion data (%p) != b->parent (%p)", 281122Smax.romanov@nginx.com data, b->parent); 282122Smax.romanov@nginx.com nxt_abort(); 283122Smax.romanov@nginx.com } 284122Smax.romanov@nginx.com #endif 285122Smax.romanov@nginx.com 286122Smax.romanov@nginx.com mp = b->data; 287122Smax.romanov@nginx.com nxt_mp_release(mp, b); 288122Smax.romanov@nginx.com 289122Smax.romanov@nginx.com if (parent != NULL) { 290122Smax.romanov@nginx.com nxt_debug(task, "parent retain:%uD", parent->retain); 291122Smax.romanov@nginx.com 292122Smax.romanov@nginx.com parent->retain--; 293122Smax.romanov@nginx.com 294122Smax.romanov@nginx.com if (parent->retain == 0) { 295122Smax.romanov@nginx.com parent->mem.pos = parent->mem.free; 296122Smax.romanov@nginx.com 297122Smax.romanov@nginx.com parent->completion_handler(task, parent, parent->parent); 298122Smax.romanov@nginx.com } 299122Smax.romanov@nginx.com } 300122Smax.romanov@nginx.com } 301*352Smax.romanov@nginx.com 302*352Smax.romanov@nginx.com 303*352Smax.romanov@nginx.com nxt_buf_t * 304*352Smax.romanov@nginx.com nxt_buf_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size) 305*352Smax.romanov@nginx.com { 306*352Smax.romanov@nginx.com nxt_buf_t *b, *i; 307*352Smax.romanov@nginx.com 308*352Smax.romanov@nginx.com if (nxt_slow_path(size == 0)) { 309*352Smax.romanov@nginx.com for (i = src; i != NULL; i = i->next) { 310*352Smax.romanov@nginx.com size += nxt_buf_used_size(i); 311*352Smax.romanov@nginx.com } 312*352Smax.romanov@nginx.com } 313*352Smax.romanov@nginx.com 314*352Smax.romanov@nginx.com b = nxt_buf_mem_alloc(mp, size, 0); 315*352Smax.romanov@nginx.com 316*352Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 317*352Smax.romanov@nginx.com return NULL; 318*352Smax.romanov@nginx.com } 319*352Smax.romanov@nginx.com 320*352Smax.romanov@nginx.com for (i = src; i != NULL; i = i->next) { 321*352Smax.romanov@nginx.com if (nxt_slow_path(nxt_buf_mem_free_size(&b->mem) < 322*352Smax.romanov@nginx.com nxt_buf_used_size(i))) { 323*352Smax.romanov@nginx.com break; 324*352Smax.romanov@nginx.com } 325*352Smax.romanov@nginx.com 326*352Smax.romanov@nginx.com b->mem.free = nxt_cpymem(b->mem.free, i->mem.pos, nxt_buf_used_size(i)); 327*352Smax.romanov@nginx.com } 328*352Smax.romanov@nginx.com 329*352Smax.romanov@nginx.com return b; 330*352Smax.romanov@nginx.com } 331