1, Role of mmap
mmap function is actually mapping physical address to virtual address, which can be operated by the process in user space, and plays the role of virtual real address conversion;
For a simple example, if some records are easy to change and you want to keep them after the program exits, you can use mmap at this time. After restarting, you can directly load the data in mmap.
2, Use of mmap function
You can check man mmap directly under ubantu
The following is part of the content
NAME
mmap, munmap - map or unmap files or devices into memory
SYNOPSIS
#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length);
mmap function sorting
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); | ||
---|---|---|
parameter | void *addr //Address | null / / the created mapping address is selected by the kernel |
Not null / / if addr is not null, the kernel will use it as a hint of the mapping location; On linux, the mapping will be created at a nearby page boundary | ||
size_t length | //Mapping space size | |
int prot //Describes the memory protection required for mapping | PROT_EXEC: page content can be executed | |
PROT_READ: page contents can be read | ||
PROT_WRITE: pages can be written | ||
PROT_NONE: page not accessible | ||
int flags | See flag list | |
int fd | Valid file descriptor | |
off_t offset | The starting point of the mapped object content | |
Return value | On successful execution, MMAP () returns a pointer to the mapped area. On failure, mmap() returns MAP_FAILED [its value is (void *)-1] | |
Error value | EACCES | Access error |
EAGAIN | The file is locked, or too much memory is locked | |
EBADF | fd is not a valid file descriptor | |
EINVAL | One or more parameters are invalid | |
ENFILE | The system limit for opening files has been reached | |
ENODEV | The file system on which the specified file resides does not support memory mapping | |
ENOMEM | There is not enough memory, or the process has exceeded the maximum number of memory mappings | |
EPERM | Insufficient power, operation not allowed | |
ETXTBSY | Open the file as written and specify MAP_DENYWRITE flag | |
SIGSEGV | Try writing to the read-only area | |
SIGBUS | Try to access a memory area that does not belong to the process |
sign | meaning |
---|---|
MAP_FIXED | //Using the specified mapping start address, if the memory area specified by the start and len parameters overlaps the existing mapping space, the overlapping part will be discarded. If the specified starting address is not available, the operation will fail. And the starting address must fall on the boundary of the page. |
MAP_SHARED | //Share the mapping space with all other processes that map this object. Writing to the shared area is equivalent to outputting to a file. Until msync() or munmap() is called, the file will not actually be updated. |
MAP_PRIVATE | //Create a private map of the copy on write. Writing to the memory area does not affect the original file. This flag and the above flags are mutually exclusive. Only one of them can be used. |
MAP_DENYWRITE | //This flag is ignored. |
MAP_EXECUTABLE | //Ibid |
MAP_NORESERVE | //Do not reserve swap space for this mapping. When the swap space is reserved, the modification of the mapping area may be guaranteed. When the swap space is not reserved and the memory is insufficient, the modification of the mapping area will cause a segment violation signal. |
MAP_LOCKED | //Lock the pages in the mapping area to prevent the pages from being swapped out of memory. |
MAP_GROWSDOWN | //Used for the stack to tell the kernel VM system that the mapping area can be expanded downward. |
MAP_ANONYMOUS | //Anonymous mapping. The mapping area is not associated with any files. |
MAP_ANON | //MAP_ANONYMOUS, another name, is no longer used. |
MAP_FILE | //Compatibility flag, ignored. |
MAP_32BIT | //Put the mapping area in the lower 2GB of the process address space, MAP_FIXED is ignored when specified. Currently, this flag is only supported on x86-64 platforms. |
MAP_POPULATE | //Prepare the page table for file mapping by pre reading. Subsequent access to the mapping area will not be blocked by page violations. |
MAP_NONBLOCK | //And map only_ Only meaningful when used with popup. Do not perform read ahead, and only create page table entries for pages that already exist in memory. |
munmap function
int munmap( void * addr, size_t len )
Upon successful execution, munmap() returns 0. In case of failure, munmap returns - 1, and the error return flag is consistent with mmap;
The call releases a mapping relationship in the process address space. addr is the address returned when calling mmap(), and len is the size of the mapping area;
When the mapping relationship is released, the access to the original mapping address will lead to segment errors.
3, mmap coding
1. Application description
mmap can only split the continuous space for mapping, so how to use the linked list for storage?
It is definitely not possible to use ordinary pointers for the following reasons,
If there is a pointer to store the address in the structure, there is no problem without restarting the software, but once the program is restarted, the address stored in the previous pointer will be invalid, and the linked list will become invalid. (personal test)
But sometimes I have to use the linked list, so after some thinking, I made some of my own designs
Add three int values to the structure. You'll know why the int value is after reading it.
//Storage structure struct mmap_st { int value; //Storage content char text[20]; //Storage content int node; //Current node int prev; //Previous node int next; //Next node };
The value text in the structure can be modified at will, but it should be noted that the string cannot be a pointer and must be of fixed size.
If your design is a one-way linked list, you only need node and next. Because my application is a two-way linked list, there is more prev.
Here is another structure used in use
struct mmap_attribute { struct mmap_st* mmap_addr; //First address of mmap storage struct mmap_st* front; //Head node struct mmap_st* now; //current node struct mmap_st* rear; //Tail node int mmap_num; //Number of queues };
create
Why save int values? First, we need to take a look at the creation of mmap
#define MMAP_FILE "/tmp/mmap" //mmap file path #define MAX_LENGTH 200 / / number of storage structures /******************************************* * @Description: create mmap * @Input: data node * @Output: data nodes * @Return: success 0 / failure - 1 * @other: * @param {mmap_attribute*} mmap_info *******************************************/ int create_mmap(struct mmap_attribute* mmap_info) { int fd = -1; int ret = -1; fd = open(MMAP_FILE, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); if (-1 == fd) { printf("can not open %s", MMAP_FILE); return -1; } lseek(fd, MAX_LENGTH * sizeof(struct mmap_st), SEEK_SET); ret = write(fd, "\0", 1); if (ret == -1) { printf("the file %s write error", MMAP_FILE); return -1; } lseek(fd, 0, SEEK_SET); mmap_info->mmap_addr = (struct mmap_st*)mmap(NULL, MAX_LENGTH * sizeof(struct mmap_st) + 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((struct mmap_st*)-1 == mmap_info->mmap_addr) { printf("mmap failed"); close(fd); return -1; } first_initialize_mmap(mmap_info); printf("create mmap success"); close(fd); return 0; } /******************************************* * @Description: initializes the mmap file when creating a file * @Input: addendum queue information * @Output: None * @Return: None * @Others: internal functions do not provide interfaces * @param {struct} mmap_attribute *******************************************/ static void first_initialize_mmap(struct mmap_attribute* mmap_info) { int i = 0; mmap_info->front = mmap_info->rear = mmap_info->mmap_addr; mmap_info->now = NULL; mmap_info->mmap_num = 0; //Set all prev node next to - 1 for (i = 0; i < MAX_LENGTH; i++) { (mmap_info->mmap_addr + i)->prev = -1; (mmap_info->mmap_addr + i)->node = -1; (mmap_info->mmap_addr + i)->next = -1; } }
We can see that when the mmap function is created, the first address of the mapping is returned. Assuming that it is addr, it is actually the address of the first structure of the structure array, so the nth element in the mmap actually exists in (addr+n). Therefore, no matter how many times we open the file, no matter how the logical address of the file changes, The address in the structure element remains the same as the first address. Then we simply need to store the offset with an int value.
When the node here is - 1, it means that when the money address does not store data, if not - 1, it stores the offset of the current position relative to the first address.
If next is - 1, it means there is no next node. If not - 1, it means the offset of the next node relative to the first address
If prev is - 1, it indicates that there is no previous node. If prev is not - 1, it indicates the offset of the previous node relative to the first address
So far, the function of the three parameters has been described, so you can use the linked list in mmap.
2. Partial function implementation function
First, let's talk about the structure that can access all variables
struct mmap_attribute { struct mmap_st* mmap_addr; //First address of mmap storage struct mmap_st* front; //Head node struct mmap_st* now; //current node struct mmap_st* rear; //Tail node int mmap_num; //Number of queues };
With mmap_addr can access the parameters in the map
The created function is already above, and the read function is below
read_mmap
/******************************************* * @Description: loads list data * @Input: mapping file header address, data header node, file size * @Output: mapping file header address, data header node * @Return: success 0 / failure - 1 * @other: * @param {struct} mmap_attribute * @param {size_t} file_size *******************************************/ int read_mmap(struct mmap_attribute* mmap_info, size_t file_size) { int fd = -1; int ret = -1; fd = open(MMAP_FILE, O_RDWR | O_CREAT, S_IRWXU); if (-1 == fd) { printf("can not open %s", MMAP_FILE); return -1; } lseek(fd, file_size - 1, SEEK_SET); ret = write(fd, "\0", 1); if (ret == -1) { printf("the file %s write error", MMAP_FILE); return -1; } lseek(fd, 0, SEEK_SET); mmap_info->mmap_addr = (struct mmap_st*)mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((struct mmap_st*)-1 == mmap_info->mmap_addr) { printf("mmap mmap failed"); close(fd); return -1; } read_initalize_mmap(mmap_info); printf("read mmap mmap success"); close(fd); return 0; } /******************************************* * @Description: read the file and initialize the mmap queue * @Input: addendum queue information * @Output: initialization queue information * @Return: None * @Others: internal functions do not provide interfaces * @param {struct} mmap_attribute *******************************************/ static void read_initalize_mmap(struct mmap_attribute* mmap_info) { struct mmap_st* pnode; //Header node found mmap_info->front = find_front_node(mmap_info->mmap_addr); if (mmap_info->front->node == -1) { mmap_info->mmap_num = 0; } else { for (pnode = mmap_info->front; pnode; pnode = ((pnode->next == -1) ? NULL : (mmap_info->mmap_addr + pnode->next))) { mmap_info->mmap_num++; } } mmap_info->now = NULL; mmap_info->rear = find_rear_node(mmap_info->mmap_addr); } /******************************************* * @Description: gets the header node in the mmap queue * @Input: mmap first address * @Output: mmap queue header node * @Return: mmap queue header node * @other: * @param {conststruct} mmap_st *******************************************/ struct mmap_st* find_front_node(struct mmap_st* mmap_addr) { int i = 0; struct mmap_st* front = NULL; for (i = 0; i < MAX_LENGTH; i++) { //If there is no previous node and the current node is not empty, it is the head node if ((mmap_addr + i)->prev == -1 && (mmap_addr + i)->node != -1) { front = mmap_addr + i; } } //If the head node is not found, it is the first address if (!front) { front = mmap_addr; } return front; } /******************************************* * @Description: gets the tail node in the mmap queue * @Input: mmap first address * @Output: mmap queue tail node * @Return: mmap queue tail node * @other: * @param {conststruct} mmap_st *******************************************/ struct mmap_st* find_rear_node(struct mmap_st* mmap_addr) { int i = 0; struct mmap_st* rear = NULL; for (i = 0; i < MAX_LENGTH; i++) { //If there is no next node and the current node is not empty, it is the tail node if ((mmap_addr + i)->next == -1 && (mmap_addr + i)->node != -1) { rear = mmap_addr + i; } } //If the tail node is not found, it is the first address if (!rear) { rear = mmap_addr; } return rear; }
mmap_num is a very useful parameter. For example, the following functions can be used
/******************************************* * @Description: judge whether the addendum queue is full * @Input: addendum queue attribute structure * @Output: information about whether the queue is full * @Return: Yes / no, false * @other: * @param {conststruct} mmap_attribute *******************************************/ bool mmap_is_full(const struct mmap_attribute* mmap_info) { return mmap_info->mmap_num == MAX_LENGTH; } /******************************************* * @Description: judge whether the addendum queue is empty * @Input: addendum queue attribute structure * @Output: information about whether the queue is empty * @Return: Yes / no, false * @other: * @param {conststruct} mmap_attribute *******************************************/ bool mmap_is_empty(const struct mmap_attribute* mmap_info) { return mmap_info->mmap_num == 0; } /******************************************* * @Description: quantity in output queue * @Input: addendum queue attribute structure * @Output: Number remaining in the addendum queue * @Return: quantity value * @other: * @param {conststruct} mmap_attribute *******************************************/ int mmap_count(const struct mmap_attribute* mmap_info) { return mmap_info->mmap_num; }
increase
/******************************************* * @Description: add mmap linked list * @Input: mmap_item addendum structure mmap_info addendum information * @Output: * @Return: success / failure false * @other: * @param {struct mmap_st} mmap_item * @param {struct} mmap_attribute *******************************************/ bool add_mmap(struct mmap_st mmap_item, struct mmap_attribute* mmap_info) { //Minimum empty address int minimum_empty_address = -1; minimum_empty_address = find_minimum_empty_address(mmap_info); printf("minimum_empty_address = %d\n", minimum_empty_address); if (minimum_empty_address == -1) { printf("add_mmap fail"); return false; } copy_to_node(mmap_item, mmap_info->mmap_addr + minimum_empty_address); (mmap_info->mmap_addr + minimum_empty_address)->prev = -1; if (mmap_info->rear->node != -1) { mmap_info->rear->next = minimum_empty_address; (mmap_info->mmap_addr + minimum_empty_address)->prev = mmap_info->rear->node; } (mmap_info->mmap_addr + minimum_empty_address)->node = minimum_empty_address; (mmap_info->mmap_addr + minimum_empty_address)->next = -1; //Update tail node mmap_info->rear = mmap_info->mmap_addr + minimum_empty_address; mmap_info->mmap_num++; return true; } /******************************************* * @Description: get the smallest empty address of the queue * @Input: addendum queue information * @Output: minimum null address value * @Return: - 1 queue full * @other: * @param {struct} mmap_attribute *******************************************/ int find_minimum_empty_address(struct mmap_attribute* mmap_info) { int i = 0; int minimum_empty_address = -1; if (mmap_is_full(mmap_info)) { printf("supply mmap is full"); return -1; } for (i = 0; i < MAX_LENGTH; i++) { if ((mmap_info->mmap_addr + i)->node == -1) { minimum_empty_address = i; break; } } return minimum_empty_address; } /******************************************* * @Description: assign a value to a node * @Input: mmap_item assignment structure, mmap_info assignment node * @Output: * @Return: None * @Others: internal function, no interface provided * @param {struct mmap_st} mmap_item * @param {struct} mmap_st *******************************************/ static void copy_to_node(struct mmap_st mmap_item, struct mmap_st* mmap_info) { //Here, the function static does not need to be declared in the header file, but it is directly declared above, but this article is put in a c file for everyone's convenience mmap_info->value = mmap_item.value; strcpy(mmap_info->text, mmap_item.text); }
Add a random queue (for test)
const unsigned char allChar[63] ="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; /******************************************* * @Description: adds a random record * @Input: * @Output: * @return: * @other: * @param {mmap_attribute*} mmap_info * @param {time_t} time_now *******************************************/ void add_one_random_schedule(struct mmap_attribute* mmap_info, time_t time_now) { struct mmap_st mmap_item; srand(time_now); mmap_item.value = rand() % 500; generateString(mmap_item.text, 15, time_now); add_mmap(mmap_item, mmap_info); } /******************************************* * @Description: gets a random string * @Input: String address, string length, time (seed) * @Output: random string * @return: * @other: * @param {unsigned char*} dest * @param {unsigned int} len * @param {time_t} time_now *******************************************/ void generate_string(unsigned char* dest, const unsigned int len, time_t time_now) { unsigned int cnt, randNo; srand(time_now); for (cnt = 0; cnt < len; cnt++) { randNo = rand() % 62; *dest = allChar[randNo]; dest++; } *dest = '\0'; }
Delete
/******************************************* * @Description: empty mmap * @Input: * @Output: * @return: * @other: * @param {mmap_attribute*} mmap_info *******************************************/ void delete_all_node(struct mmap_attribute* mmap_info) { while (mmap_info->front->node != -1) { delete_node(mmap_info->front, mmap_info); } } /******************************************* * @Description: delete the first item * @Input: * @Output: * @return: * @other: * @param {mmap_attribute*} mmap_info *******************************************/ void delete_front_node(struct mmap_attribute* mmap_info) { struct mmap_st* mmap_node; int node = 0; mmap_node = mmap_info->front; if (mmap_is_empty(mmap_info)) { printf("mmap No data in\n"); } else { node = mmap_node->node; delete_node(mmap_node, mmap_info); printf("Deleted mmap pass the civil examinations %d Data bar\n", node + 1); } }
check
/******************************************* * @Description: print addendum information * @Input: addendum structure * @Output: * @return: * @other: * @param {struct} mmap_attribute *******************************************/ void mmap_printf(struct mmap_attribute* mmap_info) { struct mmap_st* mmap_node; int flag = 1; int i = 1; printf("--------------- mmap_info ---------------\n"); if (mmap_is_empty(mmap_info)) { printf("no message in mmap\n"); } else { for (mmap_node = mmap_info->front; mmap_node; mmap_node = ((mmap_node->next == -1) ? NULL : (mmap_info->mmap_addr + mmap_node->next))) { if (flag == 1) { printf("id|value|text\n"); flag = 0; } printf("%d|%d|%s\n", i, mmap_node->value, mmap_node->text); i++; } } printf("---------------mmap_info end---------------\n"); }
4, Test case
Main function
int main() { struct mmap_attribute mmap_info; //File structure struct stat buf; int ret = 0; int i = 0, n = 0; int chose_num = 1; //Initialize the file structure size to avoid missing the file. The value is a random value buf.st_size = 0; stat(MMAP_FILE, &buf); if (buf.st_size == 0) { ret = create_mmap(&mmap_info); } else { ret = read_mmap(&mmap_info, buf.st_size); if (ret == 0) { printf("Read successful\n"); } } while (chose_num != 0) { printf("\n0:sign out\n1:see mmap\n2:insert n Random records\n3:empty mmap\n4:Delete Article 1\n"); printf("Please select:"); scanf("%d", &chose_num); switch (chose_num) { case 0: break; case 1: mmap_printf(&mmap_info); break; case 2: printf("Please enter n Value of:"); scanf("%d", &n); for (i = 0; i < n; i++) { if (mmap_is_full(&mmap_info)) { printf("mmap_is_full\n"); break; } add_one_random_schedule(&mmap_info, time(NULL) - n + i); } printf("Added %d strip\n", i); break; case 3: delete_all_node(&mmap_info); break; case 4: delete_front_node(&mmap_info); break; default: printf("Wrong choice,Reselection,(●'◡'●)\n"); break; } getchar(); if (chose_num == 0) { printf("Enter exit"); } else { printf("Press enter to continue selection"); } getchar(); } printf("Exited\n"); return 0; }
compile
gcc mmap_use.c -o mmap_test
Run test
First run
see
Here, value is a random number 0-499; Textis a 15 bit random string, sorted from beginning to end
Delete the first two
What is the offset relative to the first address
Insert five more pieces of data
You can see which addresses are the five pieces of data added
When printing, you can see that the third item is the header node
Empty queue
sign out
One is missing. Load test
Insert first, then exit
Then load and read
It can be loaded correctly
Test complete
5, Complete code
ps: for my future study and reference, or for my friends
/******************************************* * @Description : * @Author : liutt * @Date : 2021-09-14 16:13:56 * @LastEditTime : 2021-09-16 14:00:30 * @LastEditors : liutt *******************************************/ #include <fcntl.h> #include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #define MMAP_FILE "/tmp/mmap" //mmap file path #define MAX_LENGTH 200 / / number of storage structures const unsigned char allChar[63] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; //Storage structure struct mmap_st { int value; //Storage content char text[20]; //Storage content int node; //Current node int prev; //Previous node int next; //Next node }; struct mmap_attribute { struct mmap_st* mmap_addr; //First address of mmap storage struct mmap_st* front; //Head node struct mmap_st* now; //current node struct mmap_st* rear; //Tail node int mmap_num; //Number of queues }; int create_mmap(struct mmap_attribute* mmap_info); int read_mmap(struct mmap_attribute* mmap_info, size_t file_size); bool mmap_is_full(const struct mmap_attribute* mmap); bool mmap_is_empty(const struct mmap_attribute* mmap_info); int mmap_count(const struct mmap_attribute* mmap_info); static void first_initialize_mmap(struct mmap_attribute* mmap_info); struct mmap_st* find_front_node(struct mmap_st* mmap_addr); struct mmap_st* find_rear_node(struct mmap_st* mmap_addr); static void read_initalize_mmap(struct mmap_attribute* mmap_info); int find_minimum_empty_address(struct mmap_attribute* mmap_info); static void copy_to_node(struct mmap_st mmap_item, struct mmap_st* mmap_info); bool add_mmap(struct mmap_st mmap_item, struct mmap_attribute* mmap_info); void delete_node(struct mmap_st* mmap_item, struct mmap_attribute* mmap_info); static void clear_out_node(struct mmap_st* mmap_info); void mmap_printf(struct mmap_attribute* mmap_info); void generate_string(unsigned char* dest, const unsigned int len, time_t time_now); void add_one_random_schedule(struct mmap_attribute* mmap_info, time_t time_now); void delete_all_node(struct mmap_attribute* mmap_info); void delete_front_node(struct mmap_attribute* mmap_info); /******************************************* * @Description: create mmap * @Input: data node * @Output: data nodes * @Return: success 0 / failure - 1 * @other: * @param {mmap_attribute*} mmap_info *******************************************/ int create_mmap(struct mmap_attribute* mmap_info) { int fd = -1; int ret = -1; fd = open(MMAP_FILE, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); if (-1 == fd) { printf("can not open %s", MMAP_FILE); return -1; } lseek(fd, MAX_LENGTH * sizeof(struct mmap_st), SEEK_SET); ret = write(fd, "\0", 1); if (ret == -1) { printf("the file %s write error", MMAP_FILE); return -1; } lseek(fd, 0, SEEK_SET); mmap_info->mmap_addr = (struct mmap_st*)mmap(NULL, MAX_LENGTH * sizeof(struct mmap_st) + 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((struct mmap_st*)-1 == mmap_info->mmap_addr) { printf("mmap failed"); close(fd); return -1; } first_initialize_mmap(mmap_info); printf("create mmap success"); close(fd); return 0; } /******************************************* * @Description: loads list data * @Input: mapping file header address, data header node, file size * @Output: mapping file header address, data header node * @Return: success 0 / failure - 1 * @other: * @param {struct} mmap_attribute * @param {size_t} file_size *******************************************/ int read_mmap(struct mmap_attribute* mmap_info, size_t file_size) { int fd = -1; int ret = -1; fd = open(MMAP_FILE, O_RDWR | O_CREAT, S_IRWXU); if (-1 == fd) { printf("can not open %s", MMAP_FILE); return -1; } lseek(fd, file_size - 1, SEEK_SET); ret = write(fd, "\0", 1); if (ret == -1) { printf("the file %s write error", MMAP_FILE); return -1; } lseek(fd, 0, SEEK_SET); mmap_info->mmap_addr = (struct mmap_st*)mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((struct mmap_st*)-1 == mmap_info->mmap_addr) { printf("mmap mmap failed"); close(fd); return -1; } read_initalize_mmap(mmap_info); printf("read mmap mmap success"); close(fd); return 0; } /******************************************* * @Description: judge whether the addendum queue is full * @Input: addendum queue attribute structure * @Output: information about whether the queue is full * @Return: Yes / no, false * @other: * @param {conststruct} mmap_attribute *******************************************/ bool mmap_is_full(const struct mmap_attribute* mmap_info) { return mmap_info->mmap_num == MAX_LENGTH; } /******************************************* * @Description: judge whether the addendum queue is empty * @Input: addendum queue attribute structure * @Output: information about whether the queue is empty * @Return: Yes / no, false * @other: * @param {conststruct} mmap_attribute *******************************************/ bool mmap_is_empty(const struct mmap_attribute* mmap_info) { return mmap_info->mmap_num == 0; } /******************************************* * @Description: quantity in output queue * @Input: addendum queue attribute structure * @Output: Number remaining in the addendum queue * @Return: quantity value * @other: * @param {conststruct} mmap_attribute *******************************************/ int mmap_count(const struct mmap_attribute* mmap_info) { return mmap_info->mmap_num; } /******************************************* * @Description: initializes the mmap file when creating a file * @Input: addendum queue information * @Output: None * @Return: None * @Others: internal functions do not provide interfaces * @param {struct} mmap_attribute *******************************************/ static void first_initialize_mmap(struct mmap_attribute* mmap_info) { int i = 0; mmap_info->front = mmap_info->rear = mmap_info->mmap_addr; mmap_info->now = NULL; mmap_info->mmap_num = 0; //Set all prev node next to - 1 for (i = 0; i < MAX_LENGTH; i++) { (mmap_info->mmap_addr + i)->prev = -1; (mmap_info->mmap_addr + i)->node = -1; (mmap_info->mmap_addr + i)->next = -1; } } /******************************************* * @Description: gets the header node in the mmap queue * @Input: mmap first address * @Output: mmap queue header node * @Return: mmap queue header node * @other: * @param {conststruct} mmap_st *******************************************/ struct mmap_st* find_front_node(struct mmap_st* mmap_addr) { int i = 0; struct mmap_st* front = NULL; for (i = 0; i < MAX_LENGTH; i++) { if ((mmap_addr + i)->prev == -1 && (mmap_addr + i)->node != -1) { front = mmap_addr + i; } } if (!front) { front = mmap_addr; } return front; } /******************************************* * @Description: gets the tail node in the mmap queue * @Input: mmap first address * @Output: mmap queue tail node * @Return: mmap queue tail node * @other: * @param {conststruct} mmap_st *******************************************/ struct mmap_st* find_rear_node(struct mmap_st* mmap_addr) { int i = 0; struct mmap_st* rear = NULL; for (i = 0; i < MAX_LENGTH; i++) { if ((mmap_addr + i)->next == -1 && (mmap_addr + i)->node != -1) { rear = mmap_addr + i; } } if (!rear) { rear = mmap_addr; } return rear; } /******************************************* * @Description: read the file and initialize the mmap queue * @Input: addendum queue information * @Output: initialization queue information * @Return: None * @Others: internal functions do not provide interfaces * @param {struct} mmap_attribute *******************************************/ static void read_initalize_mmap(struct mmap_attribute* mmap_info) { struct mmap_st* pnode; //Header node found mmap_info->front = find_front_node(mmap_info->mmap_addr); if (mmap_info->front->node == -1) { mmap_info->mmap_num = 0; } else { for (pnode = mmap_info->front; pnode; pnode = ((pnode->next == -1) ? NULL : (mmap_info->mmap_addr + pnode->next))) { mmap_info->mmap_num++; } } mmap_info->now = NULL; mmap_info->rear = find_rear_node(mmap_info->mmap_addr); } /******************************************* * @Description: get the smallest empty address of the queue * @Input: addendum queue information * @Output: minimum null address value * @Return: - 1 queue full * @other: * @param {struct} mmap_attribute *******************************************/ int find_minimum_empty_address(struct mmap_attribute* mmap_info) { int i = 0; int minimum_empty_address = -1; if (mmap_is_full(mmap_info)) { printf("supply mmap is full"); return -1; } for (i = 0; i < MAX_LENGTH; i++) { if ((mmap_info->mmap_addr + i)->node == -1) { minimum_empty_address = i; break; } } return minimum_empty_address; } /******************************************* * @Description: assign a value to a node * @Input: mmap_item assignment structure, mmap_info assignment node * @Output: * @Return: None * @Others: internal function, no interface provided * @param {struct mmap_st} mmap_item * @param {struct} mmap_st *******************************************/ static void copy_to_node(struct mmap_st mmap_item, struct mmap_st* mmap_info) { mmap_info->value = mmap_item.value; strcpy(mmap_info->text, mmap_item.text); } /******************************************* * @Description: add mmap linked list * @Input: mmap_item addendum structure mmap_info addendum information * @Output: * @Return: success / failure false * @other: * @param {struct mmap_st} mmap_item * @param {struct} mmap_attribute *******************************************/ bool add_mmap(struct mmap_st mmap_item, struct mmap_attribute* mmap_info) { //Minimum empty address int minimum_empty_address = -1; minimum_empty_address = find_minimum_empty_address(mmap_info); printf("minimum_empty_address = %d\n", minimum_empty_address); if (minimum_empty_address == -1) { printf("add_mmap fail"); return false; } copy_to_node(mmap_item, mmap_info->mmap_addr + minimum_empty_address); (mmap_info->mmap_addr + minimum_empty_address)->prev = -1; if (mmap_info->rear->node != -1) { mmap_info->rear->next = minimum_empty_address; (mmap_info->mmap_addr + minimum_empty_address)->prev = mmap_info->rear->node; } (mmap_info->mmap_addr + minimum_empty_address)->node = minimum_empty_address; (mmap_info->mmap_addr + minimum_empty_address)->next = -1; //Update tail node mmap_info->rear = mmap_info->mmap_addr + minimum_empty_address; mmap_info->mmap_num++; return true; } void delete_node(struct mmap_st* mmap_item, struct mmap_attribute* mmap_info) { if (mmap_item->prev != -1) { (mmap_info->mmap_addr + mmap_item->prev)->next = mmap_item->next; } if (mmap_item->next != -1) { (mmap_info->mmap_addr + mmap_item->next)->prev = mmap_item->prev; } mmap_info->mmap_num--; clear_out_node(mmap_item); mmap_info->front = find_front_node(mmap_info->mmap_addr); mmap_info->rear = find_rear_node(mmap_info->mmap_addr); } /******************************************* * @Description: clears the value of a node * @Input: mmap_info addendum node * @Output: None * @Return: None * @other: * @param {struct} mmap_st *******************************************/ static void clear_out_node(struct mmap_st* mmap_info) { mmap_info->value = 0; strcpy(mmap_info->text, ""); mmap_info->node = -1; mmap_info->prev = -1; mmap_info->next = -1; } /******************************************* * @Description: print addendum information * @Input: addendum structure * @Output: * @return: * @other: * @param {struct} mmap_attribute *******************************************/ void mmap_printf(struct mmap_attribute* mmap_info) { struct mmap_st* mmap_node; int flag = 1; int i = 1; printf("--------------- mmap_info ---------------\n"); if (mmap_is_empty(mmap_info)) { printf("no message in mmap\n"); } else { for (mmap_node = mmap_info->front; mmap_node; mmap_node = ((mmap_node->next == -1) ? NULL : (mmap_info->mmap_addr + mmap_node->next))) { if (flag == 1) { printf("id|value|text\n"); flag = 0; } printf("%d|%d|%s\n", i, mmap_node->value, mmap_node->text); i++; } } printf("---------------mmap_info end---------------\n"); } /******************************************* * @Description: gets a random string * @Input: String address, string length, time (seed) * @Output: random string * @return: * @other: * @param {unsigned char*} dest * @param {unsigned int} len * @param {time_t} time_now *******************************************/ void generate_string(unsigned char* dest, const unsigned int len, time_t time_now) { unsigned int cnt, randNo; srand(time_now); for (cnt = 0; cnt < len; cnt++) { randNo = rand() % 62; *dest = allChar[randNo]; dest++; } *dest = '\0'; } /******************************************* * @Description: adds a random record * @Input: * @Output: * @return: * @other: * @param {mmap_attribute*} mmap_info * @param {time_t} time_now *******************************************/ void add_one_random_schedule(struct mmap_attribute* mmap_info, time_t time_now) { struct mmap_st mmap_item; srand(time_now); mmap_item.value = rand() % 500; generate_string(mmap_item.text, 15, time_now); add_mmap(mmap_item, mmap_info); } /******************************************* * @Description: empty mmap * @Input: * @Output: * @return: * @other: * @param {mmap_attribute*} mmap_info *******************************************/ void delete_all_node(struct mmap_attribute* mmap_info) { while (mmap_info->front->node != -1) { delete_node(mmap_info->front, mmap_info); } } /******************************************* * @Description: delete the first item * @Input: * @Output: * @return: * @other: * @param {mmap_attribute*} mmap_info *******************************************/ void delete_front_node(struct mmap_attribute* mmap_info) { struct mmap_st* mmap_node; int node = 0; mmap_node = mmap_info->front; if (mmap_is_empty(mmap_info)) { printf("mmap No data in\n"); } else { node = mmap_node->node; delete_node(mmap_node, mmap_info); printf("Deleted mmap pass the civil examinations %d Data bar\n", node + 1); } } int main() { struct mmap_attribute mmap_info; //File structure struct stat buf; int ret = 0; int i = 0, n = 0; //Initialize the file structure size to avoid missing the file. The value is a random value buf.st_size = 0; stat(MMAP_FILE, &buf); if (buf.st_size == 0) { ret = create_mmap(&mmap_info); } else { ret = read_mmap(&mmap_info, buf.st_size); if (ret == 0) { printf("Read successful\n"); } } int chose_num = 1; while (chose_num != 0) { printf("\n0:sign out\n1:see mmap\n2:insert n Random records\n3:empty mmap\n4:Delete Article 1\n"); printf("Please select:"); scanf("%d", &chose_num); switch (chose_num) { case 0: break; case 1: mmap_printf(&mmap_info); break; case 2: printf("Please enter n Value of:"); scanf("%d", &n); for (i = 0; i < n; i++) { if (mmap_is_full(&mmap_info)) { printf("mmap_is_full\n"); break; } add_one_random_schedule(&mmap_info, time(NULL) - n + i); } printf("Added %d strip\n", i); break; case 3: delete_all_node(&mmap_info); break; case 4: delete_front_node(&mmap_info); break; default: printf("Wrong choice,Reselection,(●'◡'●)\n"); break; } getchar(); if (chose_num == 0) { printf("Enter exit"); } else { printf("Press enter to continue selection"); } getchar(); } printf("Exited\n"); return 0; }
6, Write at the end
Many small partners may not know why they use mmap and linked lists. Isn't it fragrant to use arrays?
In fact, there are application scenarios, which I believe you will naturally know.
For example, I give an example, which is why I use the linked list:
For example, some operation records should be stored in this space, and the program can be reloaded after abnormal exit.
In addition, these records should be processed in a certain way, and each record has a different priority. At this time, when processing records, you can't simply take the first or last one, but find its priority, and then process it. In fact, using arrays can also solve these problems, but the disadvantage is that you have to traverse them all every time. Different people have different opinions, Let's see what our friends like~
Just use this learning record. If there are mistakes, you are welcome to criticize and correct.