Linux C language plays linked list in mmap mapping

Posted by gimzo on Sat, 18 Sep 2021 01:23:28 +0200

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);
parametervoid *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 valueOn successful execution, MMAP () returns a pointer to the mapped area. On failure, mmap() returns MAP_FAILED [its value is (void *)-1]
Error valueEACCESAccess error
EAGAINThe file is locked, or too much memory is locked
EBADF fd is not a valid file descriptor
EINVALOne or more parameters are invalid
ENFILEThe system limit for opening files has been reached
ENODEVThe file system on which the specified file resides does not support memory mapping
ENOMEMThere is not enough memory, or the process has exceeded the maximum number of memory mappings
EPERMInsufficient power, operation not allowed
ETXTBSYOpen the file as written and specify MAP_DENYWRITE flag
SIGSEGVTry writing to the read-only area
SIGBUSTry to access a memory area that does not belong to the process
signmeaning
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.

Topics: C Linux linked list