Skip to content

Instantly share code, notes, and snippets.

@byyam
Created October 24, 2019 15:11
Show Gist options
  • Save byyam/841e07516337327c0ac2560f737bed03 to your computer and use it in GitHub Desktop.
Save byyam/841e07516337327c0ac2560f737bed03 to your computer and use it in GitHub Desktop.
fifo cache demo
#include "fifo_cache.hpp"
tFifoCache::~tFifoCache()
{
if (p_cache_buffer != reinterpret_cast<char *>(-1))
{
int nRet = ::shmdt(p_cache_buffer);
if (0 != nRet)
{
std::cerr << "shmdt failed";
}
}
}
void tFifoCache::Reset()
{
p_meta_info->ShowMetaInfo();
p_meta_info->Reset();
}
int tFifoCache::Init()
{
int nShmId = ::shmget(n_key, n_total_size, IPC_CREAT|0666);
if (nShmId < 0)
{
std::cerr << " error: " << strerror(errno);
return -1;
}
p_cache_buffer = ::shmat(nShmId, NULL, 0);
if ((char *)-1 == (char *)p_cache_buffer)
{
std::cerr << " error: " << strerror(errno);
return -2;
}
p_meta_info = (tFifoCacheMeta *)p_cache_buffer;
p_meta_info->cache_size = n_total_size;
p_meta_info->usage_space = n_data_size;
p_data_buffer = (char *)p_cache_buffer + sizeof(tFifoCacheMeta);
return 0;
}
size_t tFifoCache::_GetFillLength()
{
return (((p_meta_info->tail_place + n_data_size) - p_meta_info->head_place) % n_data_size);
}
size_t tFifoCache::_GetFreeLength()
{
return (n_data_size - _GetFillLength() - 1);
}
void tFifoCache::_SetDataHead(const uint32_t nType, const size_t nLen)
{
t_data_head.data_type = nType;
t_data_head.data_len = nLen;
}
void tFifoCache::_GetDataHead(uint32_t &nType, size_t &nLen)
{
nType = t_data_head.data_type;
nLen = t_data_head.data_len;
}
void tFifoCache::_Write(const char * pBuf, const size_t nLen)
{
if (p_meta_info->head_place > p_meta_info->tail_place)
{
memcpy(&p_data_buffer[p_meta_info->tail_place], pBuf, nLen);
}
else
{
size_t nPartLen = n_data_size - p_meta_info->tail_place;
if (nPartLen < nLen)
{
memcpy(&p_data_buffer[p_meta_info->tail_place], pBuf, nPartLen);
memcpy(&p_data_buffer[0], pBuf + nPartLen, nLen - nPartLen);
}
else
{
memcpy(&p_data_buffer[p_meta_info->tail_place], pBuf, nLen);
}
}
p_meta_info->tail_place = (p_meta_info->tail_place + nLen) % n_data_size;
}
int tFifoCache::Write(const char * pBodyBuf, const size_t nBodyLen, const uint32_t nBodyType)
{
if (NULL == p_meta_info)
{
return -1;
}
if (0 == nBodyLen)
{
return -2;
}
size_t nTotalLen = nBodyLen + sizeof(tDataHead);
_SetDataHead(nBodyType, nBodyLen);
if (_GetFreeLength() < nTotalLen)
{
//full
return 1;
}
_Write((char *)&t_data_head, sizeof(tDataHead));
_Write(pBodyBuf, nBodyLen);
return 0;
}
int tFifoCache::_Peek()
{
if (_GetFillLength() < sizeof(tDataHead))
{
return 1;
}
tDataHead tTmpHead;
_Read((char *)&tTmpHead, sizeof(tDataHead), false);
if (_GetFillLength() < sizeof(tDataHead) + tTmpHead.data_len)
{
return 2;
}
return 0;
}
void tFifoCache::_Read(char *pBuf, const size_t nLen, bool bUpdatePtr)
{
if (p_meta_info->head_place < p_meta_info->tail_place)
{
memcpy(pBuf, &p_data_buffer[p_meta_info->head_place], nLen);
}
else
{
size_t nPartLen = n_data_size - p_meta_info->head_place;
if (nPartLen < nLen)
{
memcpy(pBuf, &p_data_buffer[p_meta_info->head_place], nPartLen);
memcpy(pBuf + nPartLen, &p_data_buffer[0], nLen - nPartLen);
}
else
{
memcpy(pBuf, &p_data_buffer[p_meta_info->head_place], nLen);
}
}
if (bUpdatePtr)
{
p_meta_info->head_place = (p_meta_info->head_place + nLen) % n_data_size;
}
}
int tFifoCache::Read(std::string &sBuf, uint32_t &nType)
{
int nRet = _Peek();
if (0 != nRet)
{
return nRet;
}
size_t nLen;
_Read((char *)&t_data_head, sizeof(tDataHead));
_GetDataHead(nType, nLen);
sBuf.resize(nLen);
_Read(reinterpret_cast<char *>(&sBuf[0]), nLen);
return 0;
}
#ifndef FIFO_CACHE
#define FIFO_CACHE
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/file.h>
#pragma pack(1)
struct tFifoCacheMeta
{
volatile size_t head_place;
volatile size_t tail_place;
size_t cache_size;
size_t usage_space;
tFifoCacheMeta()
{
Reset();
}
void Reset()
{
head_place = 0;
tail_place = 0;
cache_size = 0;
usage_space = 0;
}
void ShowMetaInfo(){std::cout << " head: " << head_place
<< " tail: " << tail_place
<< " size: " << cache_size
<< " usage: " << usage_space << std::endl;}
};
struct tDataHead{
uint32_t data_type;
size_t data_len;
uint32_t checksum;
};
#pragma pack()
class tFifoCache
{
public:
tFifoCache(const int32_t nKey, const size_t nUserSize)
: n_key(nKey)
{
n_data_size = nUserSize + 1;
n_total_size = n_data_size + sizeof(tFifoCacheMeta);
p_cache_buffer = reinterpret_cast<char *>(-1);
p_data_buffer = NULL;
}
virtual ~tFifoCache();
int Write(const char* buf, const size_t len, const uint32_t type);
int Read(std::string &buf, uint32_t &type);
void Reset();
int Init();
private:
int n_key;
size_t n_total_size;
size_t n_data_size;
tFifoCacheMeta *p_meta_info;
void *p_cache_buffer;
char *p_data_buffer;
tDataHead t_data_head;
size_t _GetFillLength();
size_t _GetFreeLength();
void _SetDataHead(const uint32_t nType, const size_t nLen);
void _GetDataHead(uint32_t &nType, size_t &nLen);
void _Write(const char *buf, const size_t len);
void _Read(char *buf, const size_t len, bool update_ptr = true);
int _Peek();
};
#endif
#include <stdio.h>
#include "fifo_cache.h"
#define BUF_LEN 1024*100
int main(int argc, char *argv[])
{
tFifoCache mem_obj(0x20151103, 1024*1024);
int ret = mem_obj.Init();
if (ret!=0)
{
printf("Init failed: %d\n", ret);
return -1;
}
char buf[BUF_LEN];
std::string out;
uint32_t type;
uint32_t value = 1;
while(true)
{
memcpy(buf, (void *)&value, sizeof(uint32_t));
ret = mem_obj.Write(buf, BUF_LEN, value);
if (ret) break;
printf("write value=%u\n", value);
value ++;
}
while(true)
{
ret = mem_obj.Read(out, type);
if(ret) break;
memcpy((void *)&value, out.c_str(), sizeof(uint32_t));
printf("value=%u, type=%u\n", value, type);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment