基于Linux的kfifo移植到STM32(支持os的互斥訪(fǎng)問(wèn))
關(guān)于kfifo
kfifo是內(nèi)核里面的一個(gè)First In First Out數(shù)據(jù)結(jié)構(gòu),它采用環(huán)形循環(huán)隊(duì)列的數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn);它提供一個(gè)無(wú)邊界的字節(jié)流服務(wù),最重要的一點(diǎn)是,它使用并行無(wú)鎖編程技術(shù),即當(dāng)它用于只有一個(gè)入隊(duì)線(xiàn)程和一個(gè)出隊(duì)線(xiàn)程的場(chǎng)情時(shí),兩個(gè)線(xiàn)程可以并發(fā)操作,而不需要任何加鎖行為,就可以保證kfifo的線(xiàn)程安全。
具體什么是環(huán)形緩沖區(qū),請(qǐng)看我以前的文章
說(shuō)明
關(guān)于kfifo的相關(guān)概念我不會(huì)介紹,有興趣可以看他的相關(guān)文檔,我只將其實(shí)現(xiàn)過(guò)程移植重寫(xiě),移植到適用stm32開(kāi)發(fā)板上,并且按照我個(gè)人習(xí)慣重新命名, RingBuff ->意為環(huán)形緩沖區(qū)
往期關(guān)于環(huán)形緩沖區(qū)的文章:
RingBuff_t
環(huán)形緩沖區(qū)的結(jié)構(gòu)體成員變量,具體含義看注釋。
buffer: 用于存放數(shù)據(jù)的緩存
size: buffer空間的大小
in, out: 和buffer一起構(gòu)成一個(gè)循環(huán)隊(duì)列。 in指向buffer中隊(duì)頭,而且out指向buffer中的隊(duì)尾
typedef struct ringbuff
{
uint8_t *buffer; /* 數(shù)據(jù)區(qū)域 */
uint32_t size; /* 環(huán)形緩沖區(qū)大小 */
uint32_t in; /* 數(shù)據(jù)入隊(duì)指針 (in % size) */
uint32_t out; /* 數(shù)據(jù)出隊(duì)指針 (out % size) */
#if USE_MUTEX
MUTEX_T *mutex; /* 支持rtos的互斥 */
#endif
}RingBuff_t ;
Create_RingBuff
創(chuàng)建一個(gè)環(huán)形緩沖區(qū),為了適應(yīng)后續(xù)對(duì)緩沖區(qū)入隊(duì)出隊(duì)的高效操作,環(huán)形緩沖區(qū)的大小應(yīng)為2^n字節(jié),
如果不是這個(gè)大小,則系統(tǒng)默認(rèn)裁剪以對(duì)應(yīng)緩沖區(qū)字節(jié)。
當(dāng)然還可以?xún)?yōu)化,不過(guò)我目前并未做,思路如下:如果系統(tǒng)支持動(dòng)態(tài)分配內(nèi)存,則向上對(duì)齊,避免浪費(fèi)內(nèi)存空間,否則就按照我默認(rèn)的向下對(duì)齊,當(dāng)內(nèi)存越大,對(duì)齊導(dǎo)致內(nèi)存泄漏則會(huì)越多。對(duì)齊采用的函數(shù)是roundup_pow_of_two
。如果系統(tǒng)支持互斥量,那么還將創(chuàng)建一個(gè)互斥量用來(lái)做互斥訪(fǎng)問(wèn),防止多線(xiàn)程同時(shí)使用導(dǎo)致數(shù)據(jù)丟失。
/************************************************************
* @brief Create_RingBuff
* @param rb:環(huán)形緩沖區(qū)句柄
* buffer:環(huán)形緩沖區(qū)的數(shù)據(jù)區(qū)域
* size:環(huán)形緩沖區(qū)的大小,緩沖區(qū)大小要為2^n
* @return err_t:ERR_OK表示創(chuàng)建成功,其他表示失敗
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 用于創(chuàng)建一個(gè)環(huán)形緩沖區(qū)
***********************************************************/
err_t Create_RingBuff(RingBuff_t* rb,
uint8_t *buffer,
uint32_t size
)
{
if((rb == NULL)||(buffer == NULL)||(size == 0))
{
PRINT_ERR("data is null!");
return ERR_NULL;
}
PRINT_DEBUG("ringbuff size is %d!",size);
/* 緩沖區(qū)大小必須為2^n字節(jié),系統(tǒng)會(huì)強(qiáng)制轉(zhuǎn)換,
否則可能會(huì)導(dǎo)致指針訪(fǎng)問(wèn)非法地址。
空間大小越大,強(qiáng)轉(zhuǎn)時(shí)丟失內(nèi)存越多 */
if(size&(size - 1))
{
size = roundup_pow_of_two(size);
PRINT_DEBUG("change ringbuff size is %d!",size);
}
rb->buffer = buffer;
rb->size = size;
rb->in = rb->out = 0;
#if USE_MUTEX
/* 創(chuàng)建信號(hào)量不成功 */
if(!create_mutex(rb->mutex))
{
PRINT_ERR("create mutex fail!");
ASSERT(ASSERT_ERR);
return ERR_NOK;
}
#endif
PRINT_DEBUG("create ringBuff ok!");
return ERR_OK;
}
roundup_pow_of_two
/************************************************************
* @brief roundup_pow_of_two
* @param size:傳遞進(jìn)來(lái)的數(shù)據(jù)長(zhǎng)度
* @return size:返回處理之后的數(shù)據(jù)長(zhǎng)度
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 用于處理數(shù)據(jù),使數(shù)據(jù)長(zhǎng)度必須為 2^n
* 如果不是,則轉(zhuǎn)換,丟棄多余部分,如
* roundup_pow_of_two(66) -> 返回 64
***********************************************************/
static unsigned long roundup_pow_of_two(unsigned long x)
{
return (1 << (fls(x-1)-1)); //向下對(duì)齊
//return (1UL << fls(x - 1)); //向上對(duì)齊,用動(dòng)態(tài)內(nèi)存可用使用
}
Delete_RingBuff
刪除一個(gè)環(huán)形緩沖區(qū),刪除之后,緩沖區(qū)真正存儲(chǔ)地址是不會(huì)被改變的(目前我是使用自定義數(shù)組做緩沖區(qū)的),但是刪除之后,就無(wú)法對(duì)緩沖區(qū)進(jìn)行讀寫(xiě)操作。并且如果支持os的話(huà),創(chuàng)建的互斥量會(huì)被刪除。
/************************************************************
* @brief Delete_RingBuff
* @param rb:環(huán)形緩沖區(qū)句柄
* @return err_t:ERR_OK表示成功,其他表示失敗
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 刪除一個(gè)環(huán)形緩沖區(qū)
***********************************************************/
err_t Delete_RingBuff(RingBuff_t *rb)
{
if(rb == NULL)
{
PRINT_ERR("ringbuff is null!");
return ERR_NULL;
}
rb->buffer = NULL;
rb->size = 0;
rb->in = rb->out = 0;
#if USE_MUTEX
if(!deleta_mutex(rb->mutex))
{
PRINT_DEBUG("deleta mutex is fail!");
return ERR_NOK;
}
#endif
return ERR_OK;
}
Write_RingBuff
向環(huán)形緩沖區(qū)寫(xiě)入指定數(shù)據(jù),支持線(xiàn)程互斥訪(fǎng)問(wèn)。用戶(hù)想要寫(xiě)入緩沖區(qū)的數(shù)據(jù)長(zhǎng)度不一定是真正入隊(duì)的長(zhǎng)度,在完成的時(shí)候還要看看返回值是否與用戶(hù)需要的長(zhǎng)度一致~
這個(gè)函數(shù)很有意思,也是比較高效的入隊(duì)操作,將指定區(qū)域的數(shù)據(jù)拷貝到指定的緩沖區(qū)中,過(guò)程看注釋即可
/************************************************************
* @brief Write_RingBuff
* @param rb:環(huán)形緩沖區(qū)句柄
* @param wbuff:寫(xiě)入的數(shù)據(jù)起始地址
* @param len:寫(xiě)入數(shù)據(jù)的長(zhǎng)度(字節(jié))
* @return len:實(shí)際寫(xiě)入數(shù)據(jù)的長(zhǎng)度(字節(jié))
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 這個(gè)函數(shù)會(huì)從buff空間拷貝len字節(jié)長(zhǎng)度的數(shù)據(jù)到
rb環(huán)形緩沖區(qū)中的空閑空間。
***********************************************************/
uint32_t Write_RingBuff(RingBuff_t *rb,
uint8_t *wbuff,
uint32_t len)
{
uint32_t l;
#if USE_MUTEX
/* 請(qǐng)求互斥量,成功才能進(jìn)行ringbuff的訪(fǎng)問(wèn) */
if(!request_mutex(rb->mutex))
{
PRINT_DEBUG("request mutex fail!");
return 0;
}
else /* 獲取互斥量成功 */
{
#endif
len = min(len, rb->size - rb->in + rb->out);
/* 第一部分的拷貝:從環(huán)形緩沖區(qū)寫(xiě)入數(shù)據(jù)直至緩沖區(qū)最后一個(gè)地址 */
l = min(len, rb->size - (rb->in & (rb->size - 1)));
memcpy(rb->buffer + (rb->in & (rb->size - 1)), wbuff, l);
/* 如果溢出則在緩沖區(qū)頭寫(xiě)入剩余的部分
如果沒(méi)溢出這句代碼相當(dāng)于無(wú)效 */
memcpy(rb->buffer, wbuff + l, len - l);
rb->in += len;
PRINT_DEBUG("write ringBuff len is %d!",len);
#if USE_MUTEX
}
/* 釋放互斥量 */
release_mutex(rb->mutex);
#endif
return len;
}
Read_RingBuff
讀取緩沖區(qū)數(shù)據(jù)到指定區(qū)域,用戶(hù)指定讀取長(zhǎng)度,用戶(hù)想要讀取的長(zhǎng)度不一定是真正讀取的長(zhǎng)度,在讀取完成的時(shí)候還要看看返回值是否與用戶(hù)需要的長(zhǎng)度一致~也支持多線(xiàn)程互斥訪(fǎng)問(wèn)。
也是緩沖區(qū)出隊(duì)的高效操作。過(guò)程看代碼注釋即可
/************************************************************
* @brief Read_RingBuff
* @param rb:環(huán)形緩沖區(qū)句柄
* @param wbuff:讀取數(shù)據(jù)保存的起始地址
* @param len:想要讀取數(shù)據(jù)的長(zhǎng)度(字節(jié))
* @return len:實(shí)際讀取數(shù)據(jù)的長(zhǎng)度(字節(jié))
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 這個(gè)函數(shù)會(huì)從rb環(huán)形緩沖區(qū)中的數(shù)據(jù)區(qū)域拷貝len字節(jié)
長(zhǎng)度的數(shù)據(jù)到rbuff空間。
***********************************************************/
uint32_t Read_RingBuff(RingBuff_t *rb,
uint8_t *rbuff,
uint32_t len)
{
uint32_t l;
#if USE_MUTEX
/* 請(qǐng)求互斥量,成功才能進(jìn)行ringbuff的訪(fǎng)問(wèn) */
if(!request_mutex(rb->mutex))
{
PRINT_DEBUG("request mutex fail!");
return 0;
}
else
{
#endif
len = min(len, rb->in - rb->out);
/* 第一部分的拷貝:從環(huán)形緩沖區(qū)讀取數(shù)據(jù)直至緩沖區(qū)最后一個(gè) */
l = min(len, rb->size - (rb->out & (rb->size - 1)));
memcpy(rbuff, rb->buffer + (rb->out & (rb->size - 1)), l);
/* 如果溢出則在緩沖區(qū)頭讀取剩余的部分
如果沒(méi)溢出這句代碼相當(dāng)于無(wú)效 */
memcpy(rbuff + l, rb->buffer, len - l);
rb->out += len;
PRINT_DEBUG("read ringBuff len is %d!",len);
#if USE_MUTEX
}
/* 釋放互斥量 */
release_mutex(rb->mutex);
#endif
return len;
}
獲取緩沖區(qū)信息
這些就比較簡(jiǎn)單了,看看緩沖區(qū)可讀可寫(xiě)的數(shù)據(jù)有多少
/************************************************************
* @brief CanRead_RingBuff
* @param rb:環(huán)形緩沖區(qū)句柄
* @return uint32:可讀數(shù)據(jù)長(zhǎng)度 0 / len
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 可讀數(shù)據(jù)長(zhǎng)度
***********************************************************/
uint32_t CanRead_RingBuff(RingBuff_t *rb)
{
if(NULL == rb)
{
PRINT_ERR("ringbuff is null!");
return 0;
}
if(rb->in == rb->out)
return 0;
if(rb->in > rb->out)
return (rb->in - rb->out);
return (rb->size - (rb->out - rb->in));
}
/************************************************************
* @brief CanRead_RingBuff
* @param rb:環(huán)形緩沖區(qū)句柄
* @return uint32:可寫(xiě)數(shù)據(jù)長(zhǎng)度 0 / len
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 可寫(xiě)數(shù)據(jù)長(zhǎng)度
***********************************************************/
uint32_t CanWrite_RingBuff(RingBuff_t *rb)
{
if(NULL == rb)
{
PRINT_ERR("ringbuff is null!");
return 0;
}
return (rb->size - CanRead_RingBuff(rb));
}
附帶
這里的代碼我是用于測(cè)試的,隨便寫(xiě)的
RingBuff_t ringbuff_handle;
uint8_t rb[64];
uint8_t res[64];
Create_RingBuff(&ringbuff_handle,
rb,
sizeof(rb));
Write_RingBuff(&ringbuff_handle,
res,
datapack.data_length);
PRINT_DEBUG("CanRead_RingBuff = %d!",CanRead_RingBuff(&ringbuff_handle));
PRINT_DEBUG("CanWrite_RingBuff = %d!",CanWrite_RingBuff(&ringbuff_handle));
Read_RingBuff(&ringbuff_handle,
res,
datapack.data_length);
支持多個(gè)os的互斥量操作
此處模仿了文件系統(tǒng)的互斥操作
#if USE_MUTEX
#define MUTEX_TIMEOUT 1000 /* 超時(shí)時(shí)間 */
#define MUTEX_T mutex_t /* 互斥量控制塊 */
#endif
/*********************************** mutex **************************************************/
#if USE_MUTEX
/************************************************************
* @brief create_mutex
* @param mutex:創(chuàng)建信號(hào)量句柄
* @return 創(chuàng)建成功為1,0為不成功。
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 創(chuàng)建一個(gè)互斥量,用戶(hù)在os中互斥使用ringbuff,
* 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
***********************************************************/
static err_t create_mutex(MUTEX_T *mutex)
{
err_t ret = 0;
// *mutex = rt_mutex_create("test_mux",RT_IPC_FLAG_PRIO); /* rtt */
// ret = (err_t)(*mutex != RT_NULL);
// *mutex = CreateMutex(NULL, FALSE, NULL); /* Win32 */
// ret = (err_t)(*mutex != INVALID_HANDLE_VALUE);
// *mutex = OSMutexCreate(0, &err); /* uC/OS-II */
// ret = (err_t)(err == OS_NO_ERR);
// *mutex = xSemaphoreCreateMutex(); /* FreeRTOS */
// ret = (err_t)(*mutex != NULL);
// ret = LOS_MuxCreate(&mutex); /* LiteOS */
// ret = (err_t)(ret != LOS_OK);
return ret;
}
/************************************************************
* @brief deleta_mutex
* @param mutex:互斥量句柄
* @return NULL
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 刪除一個(gè)互斥量,支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
***********************************************************/
static err_t deleta_mutex(MUTEX_T *mutex)
{
err_t ret;
// ret = rt_mutex_delete(mutex); /* rtt */
// ret = CloseHandle(mutex); /* Win32 */
// OSMutexDel(mutex, OS_DEL_ALWAYS, &err); /* uC/OS-II */
// ret = (err_t)(err == OS_NO_ERR);
// vSemaphoreDelete(mutex); /* FreeRTOS */
// ret = 1;
// ret = LOS_MuxDelete(&mutex); /* LiteOS */
// ret = (err_t)(ret != LOS_OK);
return ret;
}
/************************************************************
* @brief request_mutex
* @param mutex:互斥量句柄
* @return NULL
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 請(qǐng)求一個(gè)互斥量,得到互斥量的線(xiàn)程才允許進(jìn)行訪(fǎng)問(wèn)緩沖區(qū)
* 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
***********************************************************/
static err_t request_mutex(MUTEX_T *mutex)
{
err_t ret;
// ret = (err_t)(rt_mutex_take(mutex, MUTEX_TIMEOUT) == RT_EOK);/* rtt */
// ret = (err_t)(WaitForSingleObject(mutex, MUTEX_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
// OSMutexPend(mutex, MUTEX_TIMEOUT, &err)); /* uC/OS-II */
// ret = (err_t)(err == OS_NO_ERR);
// ret = (err_t)(xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE); /* FreeRTOS */
// ret = (err_t)(LOS_MuxPend(mutex,MUTEX_TIMEOUT) == LOS_OK); /* LiteOS */
return ret;
}
/************************************************************
* @brief release_mutex
* @param mutex:互斥量句柄
* @return NULL
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 釋放互斥量,當(dāng)線(xiàn)程使用完資源必須釋放互斥量
* 支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
***********************************************************/
static void release_mutex(MUTEX_T *mutex)
{
// rt_mutex_release(mutex);/* rtt */
// ReleaseMutex(mutex); /* Win32 */
// OSMutexPost(mutex); /* uC/OS-II */
// xSemaphoreGive(mutex); /* FreeRTOS */
// LOS_MuxPost(mutex); /* LiteOS */
}
#endif
/*********************************** mutex **************************************************/
debug.h
最后送一份debug的簡(jiǎn)便操作源碼,因?yàn)榍拔暮芏鄷r(shí)候會(huì)調(diào)用
PRINT_ERR
PRINT_DEBUG
#ifndef _DEBUG_H
#define _DEBUG_H
/************************************************************
* @brief debug.h
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 此文件用于打印日志信息
***********************************************************/
/**
* @name Debug print
* @{
*/
#define PRINT_DEBUG_ENABLE 1 /* 打印調(diào)試信息 */
#define PRINT_ERR_ENABLE 1 /* 打印錯(cuò)誤信息 */
#define PRINT_INFO_ENABLE 0 /* 打印個(gè)人信息 */
#if PRINT_DEBUG_ENABLE
#define PRINT_DEBUG(fmt, args...) do{(printf("\\n[DEBUG] >> "), printf(fmt, ##args));}while(0)
#else
#define PRINT_DEBUG(fmt, args...)
#endif
#if PRINT_ERR_ENABLE
#define PRINT_ERR(fmt, args...) do{(printf("\\n[ERR] >> "), printf(fmt, ##args));}while(0)
#else
#define PRINT_ERR(fmt, args...)
#endif
#if PRINT_INFO_ENABLE
#define PRINT_INFO(fmt, args...) do{(printf("\\n[INFO] >> "), printf(fmt, ##args));}while(0)
#else
#define PRINT_INFO(fmt, args...)
#endif
/**@} */
//針對(duì)不同的編譯器調(diào)用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include
#endif
/* 斷言 Assert */
#define AssertCalled(char,int) printf("\\nError:%s,%d\\r\\n",char,int)
#define ASSERT(x) if((x)==0) AssertCalled(__FILE__,__LINE__)
typedef enum
{
ASSERT_ERR = 0, /* 錯(cuò)誤 */
ASSERT_SUCCESS = !ASSERT_ERR /* 正確 */
} Assert_ErrorStatus;
typedef enum
{
FALSE = 0, /* 假 */
TRUE = !FALSE /* 真 */
}ResultStatus;
#endif /* __DEBUG_H */
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1416瀏覽量
41375 -
編程技術(shù)
+關(guān)注
關(guān)注
0文章
40瀏覽量
10646 -
數(shù)據(jù)結(jié)構(gòu)
+關(guān)注
關(guān)注
3文章
573瀏覽量
40724
發(fā)布評(píng)論請(qǐng)先 登錄
Linux系統(tǒng)移植開(kāi)發(fā)篇2:燒寫(xiě)linux鏡像

stm32移植linux方法
移植Linux到晶心平臺(tái)

如何將SQLite移植到linux的方法程序說(shuō)明概述
實(shí)操經(jīng)驗(yàn)分享——在STM32上移植Linux
AN3422_從STM32F1移植到STM32L1的應(yīng)用手冊(cè)

AN3427_從STM32F1移植到STM32F2的應(yīng)用手冊(cè)

Linux驅(qū)動(dòng)移植 Linux系統(tǒng)架構(gòu)優(yōu)點(diǎn)

評(píng)論