/* * Copyright (C) Igor Sysoev * Copyright (C) NGINX, Inc. */ #ifndef _NXT_BUF_H_INCLUDED_ #define _NXT_BUF_H_INCLUDED_ /* * There are four types of buffers. They are different sizes, so they * should be allocated by appropriate nxt_buf_XXX_alloc() function. * * 1) Memory-only buffers, their size is less than nxt_buf_t size, it * is equal to offsetof(nxt_buf_t, file_pos), that is it is nxt_buf_t * without file and mmap part. The buffers are frequently used, so * the reduction allows to save 20-32 bytes depending on platform. * * 2) Memory/file buffers, on Unix their size is exactly nxt_buf_t size, * since nxt_mem_map_file_ctx_t() is empty macro. On Windows the size * equals offsetof(nxt_buf_t, mmap), that is it is nxt_buf_t without * memory map context part. The buffers can contain both memory and * file pointers at once, or only memory or file pointers. * * 3) Memory mapped buffers are similar to the memory/file buffers. Their * size is exactly nxt_buf_t size. The buffers can contain both memory * and file pointers at once, or only memory or file pointers. If a * buffer is not currently mapped in memory, its mapping size is stored * in the mem.end field and available via nxt_buf_mem_size() macro. * * 4) Sync buffers, their size is the same size as memory-only buffers * size. A sync buffer can be smaller but for memory pool cache * purpose it is better to allocate it as frequently used memory-only * buffer. The buffers are used to synchronize pipeline processing * completion, because data buffers in the pipeline can be completed * and freed before their final output will even be passed to a peer. * For this purpose a sync buffer is allocated with the stop flag which * stops buffer chain completion processing on the sync buffer in * nxt_sendbuf_update() and nxt_sendbuf_completion(). * Clearing the stop flag allows to continue completion processing. * * The last flag means the end of the output and must be set only * in a sync buffer. The last flag is not permitted in memory and * file buffers since it requires special handling while conversion * one buffer to another. * * The nxt_buf_used_size() macro treats a sync buffer as a memory-only * buffer which has NULL pointers, thus the buffer content size is zero. * If allocated size of sync buffer would be lesser than memory-only * buffer, then the special memory flag would be required because * currently presence of memory part is indicated by non-NULL pointer * to a content in memory. * * All types of buffers can have the flush flag that means the buffer * should be sent as much as possible. */ typedef struct { u_char *pos; u_char *free; u_char *start; u_char *end; } nxt_buf_mem_t; struct nxt_buf_s { void *data; nxt_work_handler_t completion_handler; void *parent; /* * The next link, flags, and nxt_buf_mem_t should * reside together to improve cache locality. */ nxt_buf_t *next; uint32_t retain; uint8_t cache_hint; uint8_t is_file:1; uint8_t is_mmap:1; uint8_t is_port_mmap:1; uint8_t is_sync:1; uint8_t is_nobuf:1; uint8_t is_flush:1; uint8_t is_last:1; uint8_t is_port_mmap_sent:1; uint8_t is_ts:1; nxt_buf_mem_t mem; /* The file and mmap parts are not allocated by nxt_buf_mem_alloc(). */ nxt_file_t *file; nxt_off_t file_pos; nxt_off_t file_end; /* The mmap part is not allocated by nxt_buf_file_alloc(). */ nxt_mem_map_file_ctx_t (mmap) }; #define NXT_BUF_SYNC_SIZE offsetof(nxt_buf_t, mem.free) #define NXT_BUF_MEM_SIZE offsetof(nxt_buf_t, file) #define NXT_BUF_FILE_SIZE sizeof(nxt_buf_t) #define NXT_BUF_MMAP_SIZE NXT_BUF_FILE_SIZE #define NXT_BUF_PORT_MMAP_SIZE NXT_BUF_MEM_SIZE #define NXT_BUF_SYNC_NOBUF 1 #define NXT_BUF_SYNC_FLUSH 2 #define NXT_BUF_SYNC_LAST 4 #define nxt_buf_is_mem(b) \ ((b)->mem.pos != NULL) #define nxt_buf_is_file(b) \ ((b)->is_file) #define nxt_buf_set_file(b) \ (b)->is_file = 1 #define nxt_buf_clear_file(b) \ (b)->is_file = 0 #define nxt_buf_is_mmap(b) \ ((b)->is_mmap) #define nxt_buf_set_mmap(b) \ (b)->is_mmap = 1 #define nxt_buf_clear_mmap(b) \ (b)->is_mmap = 0 #define nxt_buf_is_port_mmap(b) \ ((b)->is_port_mmap) #define nxt_buf_set_port_mmap(b) \ (b)->is_port_mmap = 1 #define nxt_buf_clear_port_mmap(b) \ (b)->is_port_mmap = 0 #define nxt_buf_is_sync(b) \ ((b)->is_sync) #define nxt_buf_set_sync(b) \ (b)->is_sync = 1 #define nxt_buf_clear_sync(b) \ (b)->is_sync = 0 #define nxt_buf_is_nobuf(b) \ ((b)->is_nobuf) #define nxt_buf_set_nobuf(b) \ (b)->is_nobuf = 1 #define nxt_buf_clear_nobuf(b) \ (b)->is_nobuf = 0 #define nxt_buf_is_flush(b) \ ((b)->is_flush) #define nxt_buf_set_flush(b) \ (b)->is_flush = 1 #define nxt_buf_clear_flush(b) \ (b)->is_flush = 0 #define nxt_buf_is_last(b) \ ((b)->is_last) #define nxt_buf_set_last(b) \ (b)->is_last = 1 #define nxt_buf_clear_last(b) \ (b)->is_last = 0 #define nxt_buf_mem_set_size(bm, size) \ do { \ (bm)->start = 0; \ (bm)->end = (void *) size; \ } while (0) #define nxt_buf_mem_size(bm) \ ((bm)->end - (bm)->start) #define nxt_buf_mem_used_size(bm) \ ((bm)->free - (bm)->pos) #define nxt_buf_mem_free_size(bm) \ ((bm)->end - (bm)->free) #define nxt_buf_used_size(b) \ (nxt_buf_is_file(b) ? (b)->file_end - (b)->file_pos: \ nxt_buf_mem_used_size(&(b)->mem)) NXT_EXPORT void nxt_buf_mem_init(nxt_buf_t *b, void *start, size_t size); NXT_EXPORT nxt_buf_t *nxt_buf_mem_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags); NXT_EXPORT nxt_buf_t *nxt_buf_mem_ts_alloc(nxt_task_t *task, nxt_mp_t *mp, size_t size); NXT_EXPORT nxt_buf_t *nxt_buf_file_alloc(nxt_mp_t *mp, size_t size, nxt_uint_t flags); NXT_EXPORT nxt_buf_t *nxt_buf_mmap_alloc(nxt_mp_t *mp, size_t size); NXT_EXPORT nxt_buf_t *nxt_buf_sync_alloc(nxt_mp_t *mp, nxt_uint_t flags); NXT_EXPORT nxt_int_t nxt_buf_ts_handle(nxt_task_t *task, void *obj, void *data); NXT_EXPORT void nxt_buf_parent_completion(nxt_task_t *task, nxt_buf_t *parent); NXT_EXPORT nxt_buf_t *nxt_buf_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size); nxt_inline nxt_buf_t * nxt_buf_chk_make_plain(nxt_mp_t *mp, nxt_buf_t *src, size_t size) { if (nxt_slow_path(src != NULL && src->next != NULL)) { return nxt_buf_make_plain(mp, src, size); } return src; } #define nxt_buf_free(mp, b) \ nxt_mp_free((mp), (b)) NXT_EXPORT void nxt_buf_chain_add(nxt_buf_t **head, nxt_buf_t *in); NXT_EXPORT size_t nxt_buf_chain_length(nxt_buf_t *b); nxt_inline nxt_buf_t * nxt_buf_cpy(nxt_buf_t *b, const void *src, size_t length) { nxt_memcpy(b->mem.free, src, length); b->mem.free += length; return b; } nxt_inline nxt_buf_t * nxt_buf_cpystr(nxt_buf_t *b, const nxt_str_t *str) { return nxt_buf_cpy(b, str->start, str->length); } nxt_inline void nxt_buf_dummy_completion(nxt_task_t *task, void *obj, void *data) { } #endif /* _NXT_BUF_H_INCLIDED_ */