Esempio n. 1
0
bool
deq_rec::rcv_decode(rec_hdr_t h, std::ifstream* ifsp, std::size_t& rec_offs)
{
    if (rec_offs == 0)
    {
        //_deq_hdr.hdr_copy(h);
        ::rec_hdr_copy(&_deq_hdr._rhdr, &h);
        ifsp->read((char*)&_deq_hdr._deq_rid, sizeof(uint64_t));
        ifsp->read((char*)&_deq_hdr._xidsize, sizeof(std::size_t));
#if defined(JRNL_32_BIT)
        ifsp->ignore(sizeof(uint32_t)); // _filler0
#endif
        rec_offs = sizeof(_deq_hdr);
        // Read header, allocate (if req'd) for xid
        if (_deq_hdr._xidsize)
        {
            _buff = std::malloc(_deq_hdr._xidsize);
            MALLOC_CHK(_buff, "_buff", "enq_rec", "rcv_decode");
        }
    }
    if (rec_offs < sizeof(_deq_hdr) + _deq_hdr._xidsize)
    {
        // Read xid (or continue reading xid)
        std::size_t offs = rec_offs - sizeof(_deq_hdr);
        ifsp->read((char*)_buff + offs, _deq_hdr._xidsize - offs);
        std::size_t size_read = ifsp->gcount();
        rec_offs += size_read;
        if (size_read < _deq_hdr._xidsize - offs)
        {
            assert(ifsp->eof());
            // As we may have read past eof, turn off fail bit
            ifsp->clear(ifsp->rdstate()&(~std::ifstream::failbit));
            assert(!ifsp->fail() && !ifsp->bad());
            return false;
        }
    }
    if (rec_offs < sizeof(_deq_hdr) +
            (_deq_hdr._xidsize ? _deq_hdr._xidsize + sizeof(rec_tail_t) : 0))
    {
        // Read tail (or continue reading tail)
        std::size_t offs = rec_offs - sizeof(_deq_hdr) - _deq_hdr._xidsize;
        ifsp->read((char*)&_deq_tail + offs, sizeof(rec_tail_t) - offs);
        std::size_t size_read = ifsp->gcount();
        rec_offs += size_read;
        if (size_read < sizeof(rec_tail_t) - offs)
        {
            assert(ifsp->eof());
            // As we may have read past eof, turn off fail bit
            ifsp->clear(ifsp->rdstate()&(~std::ifstream::failbit));
            assert(!ifsp->fail() && !ifsp->bad());
            return false;
        }
    }
    ifsp->ignore(rec_size_dblks() * QLS_DBLK_SIZE_BYTES - rec_size());
    if (_deq_hdr._xidsize)
        chk_tail(); // Throws if tail invalid or record incomplete
    assert(!ifsp->fail() && !ifsp->bad());
    return true;
}
Esempio n. 2
0
void
pmgr::initialize(aio_callback* const cbp, const uint32_t cache_pgsize_sblks, const uint16_t cache_num_pages)
{
    // As static use of this class keeps old values around, clean up first...
    pmgr::clean();
    _pg_index = 0;
    _pg_cntr = 0;
    _pg_offset_dblks = 0;
    _aio_evt_rem = 0;
    _cache_pgsize_sblks = cache_pgsize_sblks;
    _cache_num_pages = cache_num_pages;
    _cbp = cbp;

    // 1. Allocate page memory (as a single block)
    std::size_t cache_pgsize = _cache_num_pages * _cache_pgsize_sblks * _sblkSizeBytes;
    if (::posix_memalign(&_page_base_ptr, QLS_AIO_ALIGN_BOUNDARY_BYTES, cache_pgsize))
    {
        clean();
        std::ostringstream oss;
        oss << "posix_memalign(): alignment=" << QLS_AIO_ALIGN_BOUNDARY_BYTES << " size=" << cache_pgsize;
        oss << FORMAT_SYSERR(errno);
        throw jexception(jerrno::JERR__MALLOC, oss.str(), "pmgr", "initialize");
    }

    // 2. Allocate array of page pointers
    _page_ptr_arr = (void**)std::malloc(_cache_num_pages * sizeof(void*));
    MALLOC_CHK(_page_ptr_arr, "_page_ptr_arr", "pmgr", "initialize");

    // 3. Allocate and initialize page control block (page_cb) array
    _page_cb_arr = (page_cb*)std::malloc(_cache_num_pages * sizeof(page_cb));
    MALLOC_CHK(_page_cb_arr, "_page_cb_arr", "pmgr", "initialize");
    std::memset(_page_cb_arr, 0, _cache_num_pages * sizeof(page_cb));

    // 4. Allocate IO control block (iocb) array
    _aio_cb_arr = (aio_cb*)std::malloc(_cache_num_pages * sizeof(aio_cb));
    MALLOC_CHK(_aio_cb_arr, "_aio_cb_arr", "pmgr", "initialize");

    // 5. Set page pointers in _page_ptr_arr, _page_cb_arr and iocbs to pages within page block
    for (uint16_t i=0; i<_cache_num_pages; i++)
    {
        _page_ptr_arr[i] = (void*)((char*)_page_base_ptr + _cache_pgsize_sblks * _sblkSizeBytes * i);
        _page_cb_arr[i]._index = i;
        _page_cb_arr[i]._state = UNUSED;
        _page_cb_arr[i]._pbuff = _page_ptr_arr[i];
        _page_cb_arr[i]._pdtokl = new std::deque<data_tok*>;
        _page_cb_arr[i]._pdtokl->clear();
        _aio_cb_arr[i].data = (void*)&_page_cb_arr[i];
    }

    // 6. Allocate io_event array, max one event per cache page plus one for each file
    const uint16_t max_aio_evts = _cache_num_pages + 1; // One additional event for file header writes
    _aio_event_arr = (aio_event*)std::malloc(max_aio_evts * sizeof(aio_event));
    MALLOC_CHK(_aio_event_arr, "_aio_event_arr", "pmgr", "initialize");

    // 7. Initialize AIO context
    if (int ret = aio::queue_init(max_aio_evts, &_ioctx))
    {
        std::ostringstream oss;
        oss << "io_queue_init() failed: " << FORMAT_SYSERR(-ret);
        throw jexception(jerrno::JERR__AIO, oss.str(), "pmgr", "initialize");
    }
}
Esempio n. 3
0
/** Link the given file into flash ROM.
 * \param programfile Filename containing program to load
 * \param symtabfile  File containing the symbol table of the kernel
 * \param process     Output for storing pointer to process structure
 *                    of program
 * \return 0 on success, 1 if file was damaged or not found, 2 if not
 *         enough memory, 3 if symbol could not be resolved
 */
uint_fast8_t minilink_load(const char *programfile, const char *symtabfile, struct process ***proclist) {
	Minilink_Header mlhdr;
	uint16_t *symvalp = NULL;
	Minilink_ProgramInfoHeader pihdr, *instprog;
	int status = 1;

	struct io_buf_st buf_ml;
	struct io_buf_st buf_sym;

#if DEBUG_DIFF
	void * memblock;
	memblock = malloc(node_id * 40);
#endif

	LEDGOFF;
	LEDBOFF;
	LEDRON;
	memset(&pihdr, 0, sizeof(pihdr));

	if (strlen(programfile) > MINILINK_MAX_FILENAME - 1) {

		DPUTS("Name too long.\n");
		return 1;
	}

	buf_ml.filled = 0;
	buf_ml.pos = 0;

	LEDBON;
	buf_ml.fd = cfs_open(programfile, CFS_READ);

	if (buf_ml.fd < 0) {
		DPUTS("Could not open File.");
		goto cleanup;
	}

	buf_sym.pos = 0;
	buf_sym.filled = 0;

	buf_sym.fd = cfs_open(symtabfile, CFS_READ);
	LEDBOFF;

	//Check whether the files are ok
	if (ml_file_check(buf_ml.fd, MINILINK_PGM_MAGIC) != 1) {
		DPUTS("Ret is not 1\n");
		return 1;
	}

	if (ml_file_check(buf_sym.fd, MINILINK_SYM_MAGIC) != 1) {
		DPUTS("Ret is not 1\n");
		return 1;
	}
	LEDGON;

	//Reset
	cfs_seek(buf_ml.fd, 0, CFS_SEEK_SET);
	cfs_seek(buf_sym.fd, 0, CFS_SEEK_SET);
	LEDBON;

	//Read header, but do not write to buffer!
	if (cfs_read(buf_ml.fd, &mlhdr, sizeof(mlhdr)) != sizeof(mlhdr)) {
		DPUTS("Could not Read Header.");
		goto cleanup;
	}

	//Now let's get the ram for the symbol table
	symvalp = malloc(mlhdr.symentries * sizeof(uint16_t));
	if (symvalp == NULL) {
		DPUTS("Could not allocate memory for symtbl.");
		status = 2;
		goto cleanup;
	}

	//------------ Resolve the symbol-list. - This must be done anyway
	{
		uint16_t symctr;

		char cursym[MINILINK_MAX_SYMLEN];
		uint16_t curr_add = 0;

		cursym[0] = 0;

		if (buf_sym.fd < 0) {
			DPUTS("Could not open File.");
			goto cleanup;
		}
		{ //get rid of the header.
			uint8_t shift = sizeof(Minilink_SymbolHeader);
			while (shift) {
				shift_iobuf(&buf_sym);
				buf_sym.pos = Min(buf_sym.filled, shift);
				shift -= buf_sym.pos;
			}
		}

		//Fill Buffer.....
		shift_iobuf(&buf_sym);

#define NEXTSYMPOS {buf_sym.pos++; if(buf_sym.filled == buf_sym.pos) shift_iobuf(&buf_sym);}

		for (symctr = 0; symctr < mlhdr.symentries; symctr++) {
			uint8_t samechars;

			//fill buffer.
			shift_iobuf(&buf_ml);
			samechars = buf_ml.data[buf_ml.pos];
			buf_ml.pos++;
			DPRINTF("Looking up: <%i>%s\n", samechars, &(buf_ml.data[buf_ml.pos]));

			while (1) {
				/// \fixme make sure we don't go past the buffer
				// The next code is a bit complicated, I'll add some graphix to visualize it
				/// \todo Grafiken erstellen.
				//get next symbol
				uint8_t symattr;
				uint16_t sym_write_pos;

				symattr = buf_sym.data[buf_sym.pos];
				NEXTSYMPOS;

				sym_write_pos = symattr & 0x3F;

				if (samechars > sym_write_pos) { //Ok, looks like we went past the symbol
					DPUTS("Symbol could not be resolved - past same\n");
					status = 1;
					goto cleanup;
				} else if (samechars == sym_write_pos) {
					while (1) { //Loop until we reach the Null-char
						if (buf_sym.data[buf_sym.pos] != buf_ml.data[buf_ml.pos]) break;

						if (buf_ml.data[buf_ml.pos] == '\0') {
							DPUTS("FOUND!\n");
							break; //Could take any of the two, as they are the same
						}
						//It is important that this comes afterwards! - It must point at the NULL
						NEXTSYMPOS;
						buf_ml.pos++;
						samechars++;

					}

					if (buf_sym.data[buf_sym.pos] > buf_ml.data[buf_ml.pos]) { // We are searching for a symbol smaller then
						// the current on. - They are sorted, therefore we will not find it anymore

						DPUTS("Symbol could not be resolved - past alpha\n");
						status = 3;
						goto cleanup;
					}

				}

				while (buf_sym.data[buf_sym.pos] != '\0') NEXTSYMPOS;
				NEXTSYMPOS; //one more!

				symattr &= 0xC0;
				symattr >>= 6;

				switch (symattr) {
				case 0:
					CPY16(curr_add, buf_sym.data[buf_sym.pos]);
					NEXTSYMPOS;
					break;
				case 1:
					curr_add--;
					curr_add -= buf_sym.data[buf_sym.pos];
					break;
				case 3:
					curr_add += 0x0100;
				case 2:
					curr_add += buf_sym.data[buf_sym.pos];
					break;
				}
				NEXTSYMPOS;

				//DPRINTF("Checking: %i:%s - %x same: %i\n",buf_sym.data[0] & 0x3F , &(buf_sym.data[1]), curr_add, samechars);

				//We've found the symbol, so let's break
				if (buf_ml.data[buf_ml.pos] == '\0') {
					//Move on to next symbol.
					buf_ml.pos++;
					break;
				}
			} //Loop searching for the symbol

			((uint16_t *) (symvalp))[symctr] = curr_add; //copy the symbol address to memory
			MALLOC_CHK(symvalp);
		} //Loop looping through symbols
	} // End of resolving symbol list.
#undef NEXTSYMPOS
	LEDGOFF;

	pihdr.magic = MINILINK_INST_MAGIC;
	pihdr.crc = mlhdr.common.crc;
	//pihdr.mem[DATA].ptr = NULL;
	pihdr.mem[MINILINK_DATA].size = mlhdr.datasize;
	//pihdr.mem[MINILINK_BSS].ptr = NULL;
	pihdr.mem[MINILINK_BSS].size = mlhdr.bsssize;
	//pihdr.mem[MINILINK_MIG].ptr = NULL;
	pihdr.mem[MINILINK_MIG].size = mlhdr.migsize;
	//pihdr.mem[MINILINK_MIGPTR].ptr = NULL;
	pihdr.mem[MINILINK_MIGPTR].size = mlhdr.migptrsize;
	//pihdr.process = NULL;
	pihdr.mem[MINILINK_TEXT].size = mlhdr.textsize;
	strncpy(pihdr.sourcefile, programfile, MINILINK_MAX_FILENAME);

	//Let's see whether the program is already installed
	instprog = program_already_loaded(&pihdr);

	if (instprog != NULL) {
		struct process * curproc;
		/* Check if program to be reloaded has active processes, i.e. appears
		 * in the process list
		 */
		for (curproc = process_list; curproc != NULL; curproc = curproc->next) {
			if ((uintptr_t) (void*) curproc >= (uintptr_t)(instprog->mem[MINILINK_DATA].ptr)
					&& (uintptr_t) (void*) curproc < (uintptr_t)(instprog->mem[MINILINK_DATA].ptr + instprog->mem[MINILINK_DATA].size)) {
				puts("Process in use. Can't install.");
				status = 2;
				goto cleanup;
			}
		}

		DPRINTF("Loading header from %x\n Data: %x\nBss: %x\n", (uint16_t ) instprog, (uint16_t)instprog->mem[MINILINK_DATA].ptr,
				(uint16_t)instprog->mem[MINILINK_BSS].ptr);

		memcpy(&pihdr, instprog, sizeof(pihdr));
		DPRINTF("After copy:\n Data: %x\nBss: %x\n", (uint16_t)(pihdr.mem[MINILINK_DATA].ptr), (uint16_t)pihdr.mem[MINILINK_BSS].ptr);
		pihdr.mem[MINILINK_TEXT].ptr = (uint8_t *) instprog + sizeof(pihdr);
	}

	else { //Process does not exist, let's get some memory for linking it
		status = 2;
		uint8_t ctr;
		//Now let's allocate Memory
		if ((mlhdr.textsize & 1) || (mlhdr.datasize & 1) || (mlhdr.bsssize & 1)) {
			DPUTS(".data, .bss or .text section not word aligned");
			goto cleanup;
		}

		pihdr.mem[MINILINK_TEXT].ptr = ml_alloc_text(pihdr.mem[MINILINK_TEXT].size + sizeof(pihdr));
		if (pihdr.mem[MINILINK_TEXT].ptr == NULL) {
			DPUTS("Could not alloc Text.");
			goto cleanup;
		}
		pihdr.mem[MINILINK_TEXT].ptr += sizeof(pihdr);

		//Allocate Memory; Starting beheind text
		for (ctr = MINILINK_DATA; ctr < MINILINK_SEC; ctr++) {
			if (pihdr.mem[ctr].size) {
				pihdr.mem[ctr].ptr = ml_alloc_mem(mlhdr.datasize);
				if (pihdr.mem[ctr].ptr == NULL) {
					DPRINTF("Could not alloc Memory for %i\n", ctr);
					goto cleanup;
				}
			}
		}

		pihdr.process = pihdr.mem[MINILINK_TEXT].ptr + mlhdr.processoffset;
		DPRINTF("PO: %.4x = %.4x + %.4x\n", (uintptr_t )pihdr.process, (uintptr_t)pihdr.mem[MINILINK_TEXT].ptr, mlhdr.processoffset);

	}

	// Build up array where to place what....

	{
		uint8_t r;
		for (r = 0; r < MINILINK_SEC; r++) {
			DPRINTF("%x len: %x\n", (uintptr_t)(pihdr.mem[r].ptr), (uintptr_t)(pihdr.mem[r].size));
		}
	}
	LEDBOFF;

	// Link data section
	DPRINTF("\n\nRelocating DATA to %x len: %x\n", (uint16_t)pihdr.mem[MINILINK_DATA].ptr, (uint16_t)pihdr.mem[MINILINK_DATA].size);
	status = ml_relocate(&buf_ml, pihdr.mem[MINILINK_DATA].size, pihdr.mem[MINILINK_DATA].ptr, symvalp, mlhdr.symentries, &pihdr, NULL);
	if (status != 0) goto cleanup;
	MALLOC_CHK(symvalp);
	// Link mig section
	if (mlhdr.migsize) {
		DPRINTF("\n\nRelocating MIG to %x len: %x\n", (uint16_t)pihdr.mem[MINILINK_MIG].ptr, (uint16_t)pihdr.mem[MINILINK_MIG].size);
		status = ml_relocate(&buf_ml, pihdr.mem[MINILINK_MIG].size, pihdr.mem[MINILINK_MIG].ptr, symvalp, mlhdr.symentries, &pihdr, NULL);
		if (status != 0) goto cleanup;
	}
	MALLOC_CHK(symvalp);
	// Link migptr section
	if (mlhdr.migptrsize) {
		DPRINTF("\n\nRelocating MIG to %x len: %x\n", (uint16_t)pihdr.mem[MINILINK_MIGPTR].ptr, (uint16_t)pihdr.mem[MINILINK_MIGPTR].size);
		status = ml_relocate(&buf_ml, pihdr.mem[MINILINK_MIGPTR].size, pihdr.mem[MINILINK_MIGPTR].ptr, symvalp, mlhdr.symentries, &pihdr, NULL);
		if (status != 0) goto cleanup;
	}
	MALLOC_CHK(symvalp);
	//Set Bss to 0
	if (mlhdr.bsssize) {
		DPRINTF("\n\nClearing BSS at %x\n", (uint16_t) pihdr.mem[MINILINK_BSS].ptr);
		memset(pihdr.mem[MINILINK_BSS].ptr, 0, pihdr.mem[MINILINK_BSS].size);
	}

	LEDGON;
	if (instprog == NULL) {
		DPRINTF("\n\nRelocating ROM to %x len: %x\n", (uint16_t) pihdr.mem[MINILINK_TEXT].ptr, (uint16_t ) mlhdr.textsize);
		//Buf ML is positioned behind the symbol table
		status = ml_relocate(&buf_ml, mlhdr.textsize, pihdr.mem[MINILINK_TEXT].ptr, symvalp, mlhdr.symentries, &pihdr, &memwrite_flash);
		if (status != 0) goto cleanup;
		MALLOC_CHK(symvalp);

		DPRINTF("\n\nWriting header to %x\n", (uint16_t)pihdr.mem[MINILINK_TEXT].ptr - sizeof(pihdr));
		memwrite_flash(pihdr.mem[MINILINK_TEXT].ptr - sizeof(pihdr), &pihdr, sizeof(pihdr));
		//if(memcmp(pTxt - sizeof(pihdr), &pihdr, sizeof(pihdr)) != 0) printf("\n\nPANIC!!!\n\n");
		{
			Minilink_ProgramInfoHeader *tmp, *tmp2;
			tmp2 = &pihdr;
			tmp = pihdr.mem[MINILINK_TEXT].ptr - sizeof(pihdr);
			//printf("PIHproc: %x - %x\n", (uint16_t)(tmp->process), (uint16_t)(tmp2->process));
		}

		if (status != 0) goto cleanup;
	}
	LEDROFF;
	LEDGOFF;

	*proclist = pihdr.process;
	DPUTS("Loading complete.");

	cleanup:
#if DEBUG_DIFF
	free(memblock);
#endif
	free(symvalp);
	cfs_close(buf_ml.fd);
	cfs_close(buf_sym.fd);
	if (status != 0) {
		uint8_t ctr;
		//No flash
		for (ctr = 1; ctr < MINILINK_SEC; ctr++) {
			ml_free_mem(pihdr.mem[ctr].ptr);
		}
	}

	return status;
}
Esempio n. 4
0
uint32_t
deq_rec::decode(rec_hdr_t& h, void* rptr, uint32_t rec_offs_dblks, uint32_t max_size_dblks)
{
    assert(rptr != 0);
    assert(max_size_dblks > 0);

    std::size_t rd_cnt = 0;
    if (rec_offs_dblks) // Continuation of record on new page
    {
        const uint32_t hdr_xid_dblks = size_dblks(sizeof(deq_hdr_t) + _deq_hdr._xidsize);
        const uint32_t hdr_xid_tail_dblks = size_dblks(sizeof(deq_hdr_t) + _deq_hdr._xidsize +
                sizeof(rec_tail_t));
        const std::size_t rec_offs = rec_offs_dblks * QLS_DBLK_SIZE_BYTES;

        if (hdr_xid_tail_dblks - rec_offs_dblks <= max_size_dblks)
        {
            // Remainder of xid fits within this page
            if (rec_offs - sizeof(deq_hdr_t) < _deq_hdr._xidsize)
            {
                // Part of xid still outstanding, copy remainder of xid and tail
                const std::size_t xid_offs = rec_offs - sizeof(deq_hdr_t);
                const std::size_t xid_rem = _deq_hdr._xidsize - xid_offs;
                std::memcpy((char*)_buff + xid_offs, rptr, xid_rem);
                rd_cnt = xid_rem;
                std::memcpy((void*)&_deq_tail, ((char*)rptr + rd_cnt), sizeof(_deq_tail));
                chk_tail();
                rd_cnt += sizeof(_deq_tail);
            }
            else
            {
                // Tail or part of tail only outstanding, complete tail
                const std::size_t tail_offs = rec_offs - sizeof(deq_hdr_t) - _deq_hdr._xidsize;
                const std::size_t tail_rem = sizeof(rec_tail_t) - tail_offs;
                std::memcpy((char*)&_deq_tail + tail_offs, rptr, tail_rem);
                chk_tail();
                rd_cnt = tail_rem;
            }
        }
        else if (hdr_xid_dblks - rec_offs_dblks <= max_size_dblks)
        {
            // Remainder of xid fits within this page, tail split
            const std::size_t xid_offs = rec_offs - sizeof(deq_hdr_t);
            const std::size_t xid_rem = _deq_hdr._xidsize - xid_offs;
            std::memcpy((char*)_buff + xid_offs, rptr, xid_rem);
            rd_cnt += xid_rem;
            const std::size_t tail_rem = (max_size_dblks * QLS_DBLK_SIZE_BYTES) - rd_cnt;
            if (tail_rem)
            {
                std::memcpy((void*)&_deq_tail, ((char*)rptr + xid_rem), tail_rem);
                rd_cnt += tail_rem;
            }
        }
        else
        {
            // Remainder of xid split
            const std::size_t xid_cp_size = (max_size_dblks * QLS_DBLK_SIZE_BYTES);
            std::memcpy((char*)_buff + rec_offs - sizeof(deq_hdr_t), rptr, xid_cp_size);
            rd_cnt += xid_cp_size;
        }
    }
    else // Start of record
    {
        // Get and check header
        //_deq_hdr.hdr_copy(h);
        ::rec_hdr_copy(&_deq_hdr._rhdr, &h);
        rd_cnt = sizeof(rec_hdr_t);
        std::memcpy(&_deq_hdr._deq_rid, (char*)rptr + rd_cnt, sizeof(u_int64_t));
        rd_cnt += sizeof(uint64_t);
        std::memcpy(&_deq_hdr._xidsize, (char*)rptr + rd_cnt, sizeof(std::size_t));
        rd_cnt = sizeof(deq_hdr_t);
        chk_hdr();
        if (_deq_hdr._xidsize)
        {
            _buff = std::malloc(_deq_hdr._xidsize);
            MALLOC_CHK(_buff, "_buff", "deq_rec", "decode");
            const uint32_t hdr_xid_dblks = size_dblks(sizeof(deq_hdr_t) + _deq_hdr._xidsize);
            const uint32_t hdr_xid_tail_dblks = size_dblks(sizeof(deq_hdr_t) +  _deq_hdr._xidsize +
                    sizeof(rec_tail_t));

            // Check if record (header + xid + tail) fits within this page, we can check the
            // tail before the expense of copying data to memory
            if (hdr_xid_tail_dblks <= max_size_dblks)
            {
                // Entire header, xid and tail fits within this page
                std::memcpy(_buff, (char*)rptr + rd_cnt, _deq_hdr._xidsize);
                rd_cnt += _deq_hdr._xidsize;
                std::memcpy((void*)&_deq_tail, (char*)rptr + rd_cnt, sizeof(_deq_tail));
                rd_cnt += sizeof(_deq_tail);
                chk_tail();
            }
            else if (hdr_xid_dblks <= max_size_dblks)
            {
                // Entire header and xid fit within this page, tail split
                std::memcpy(_buff, (char*)rptr + rd_cnt, _deq_hdr._xidsize);
                rd_cnt += _deq_hdr._xidsize;
                const std::size_t tail_rem = (max_size_dblks * QLS_DBLK_SIZE_BYTES) - rd_cnt;
                if (tail_rem)
                {
                    std::memcpy((void*)&_deq_tail, (char*)rptr + rd_cnt, tail_rem);
                    rd_cnt += tail_rem;
                }
            }
            else
            {
                // Header fits within this page, xid split
                const std::size_t xid_cp_size = (max_size_dblks * QLS_DBLK_SIZE_BYTES) - rd_cnt;
                std::memcpy(_buff, (char*)rptr + rd_cnt, xid_cp_size);
                rd_cnt += xid_cp_size;
            }
        }
    }
    return size_dblks(rd_cnt);
}