Подтвердить что ты не робот

Могу ли я сделать memcpy для копирования на запись в Linux?

У меня есть код, в котором я часто копирую большой блок памяти, часто после внесения в него только очень небольших изменений.

Я внедрил систему, которая отслеживает изменения, но я подумал, что было бы неплохо, если бы можно было сказать ОС, чтобы сделать "копирование на запись" в памяти, и пусть это касается только создания копии из тех частей, которые меняются. Однако, в то время как Linux делает копию на запись, например, когда fork() ing, я не могу найти способ контролировать это и делать это сам.

4b9b3361

Ответ 1

Ваш лучший шанс, вероятно, состоит в mmap() исходных данных в файл, а затем mmap() тот же файл снова с помощью MAP_PRIVATE.

Ответ 3

Используемый механизм копирования на запись, например, fork() - это функция MMU (Unit Management Unit Unit), которая обрабатывает пейджинг памяти для ядра. Доступ к MMU является привилегированной операцией, т.е. Не может выполняться приложением пользовательского пространства. Я не знаю, какой API-адрес для копирования на запись экспортируется в пользовательское пространство.

(Опять же, я не являюсь гуру в API Linux, поэтому другие могут указывать на соответствующие вызовы API, которые я пропустил.)

Изменить: И вот, MSalters поднимается по этому поводу.; -)

Ответ 4

Его проще реализовать copy-on-write на объектно-ориентированном языке, например С++. Например, большинство классов контейнеров в Qt являются copy-on-write.

Но если вы тоже можете это сделать в C, это еще какая-то работа. Когда вы хотите назначить свои данные новому блоку данных, вы не делаете копии, вместо этого вы просто скопируете указатель в узле обертки вокруг ваших данных. Вам необходимо отслеживать в своих блоках данных статус данных. Если вы сейчас что-то измените в своем новом блоке данных, вы сделаете "реальную" копию и измените статус. Вы, конечно, не можете больше использовать простые операторы типа "=" для назначения, вместо этого должны иметь функции (в С++ вы просто выполняете перегрузку оператора).

Более надежная реализация должна использовать контрольные счетчики вместо простого флага, я оставлю это вам.

Быстрый и грязный пример: Если у вас есть

struct big {
//lots of data
    int data[BIG_NUMBER];
}

вам нужно реализовать функции назначения и getters/seters самостоятельно.

// assume you want to implent cow for a struct big of some kind
// now instead of
struct big a, b;
a = b;
a.data[12345] = 6789;

// you need to use
struct cow_big a,b;
assign(&a, b);   //only pointers get copied
set_some_data(a, 12345, 6789); // now the stuff gets really copied


//the basic implementation could look like 
struct cow_big {
    struct big *data;
    int needs_copy;
}

// shallow copy, only sets a pointer. 
void assign(struct cow_big* dst, struct cow_big src) {
    dst->data = src.data;
    dst->needs_copy = true;
}

// change some data in struct big. if it hasn't made a deep copy yet, do it here.
void set_some_data(struct cow_big* dst, int index, int data } {
    if (dst->needs_copy) {
        struct big* src = dst->data;
        dst->data = malloc(sizeof(big));
        *(dst->data) = src->data;   // now here is the deep copy
       dst->needs_copy = false;
   }
   dst->data[index] = data;
}

Вам также нужно написать конструкторы и деструкторы. Я действительно рекомендую С++ для этого.

Ответ 5

Вы можете открыть свою собственную память через /proc/ $PID/mem, а затем mmap() интересную ее часть с MAP_PRIVATE в другое место.

Ответ 6

Вот рабочий пример:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SIZE 4096

int main(void) {
  int fd = shm_open("/tmpmem", O_RDWR | O_CREAT, 0666);
  int r = ftruncate(fd, SIZE);
  printf("fd: %i, r: %i\n", fd, r);
  char *buf = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
      MAP_SHARED, fd, 0);
  printf("debug 0\n");
  buf[SIZE - 2] = 41;
  buf[SIZE - 1] = 42;
  printf("debug 1\n");

  // don't know why this is needed, or working
  //r = mmap(buf, SIZE, PROT_READ | PROT_WRITE,
  //  MAP_FIXED, fd, 0);
  //printf("r: %i\n", r);

  char *buf2 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
    MAP_PRIVATE, fd, 0);
  printf("buf2: %i\n", buf2);
  buf2[SIZE - 1] = 43;
  buf[SIZE - 2] = 40;
  printf("buf[-2]: %i, buf[-1]: %i, buf2[-2]: %i, buf2[-1]: %i\n",
      buf[SIZE - 2],
      buf[SIZE - 1],
      buf2[SIZE - 2],
      buf2[SIZE - 1]);

  unlink(fd);
  return EXIT_SUCCESS;
}

Я немного сомневаюсь в том, что мне нужно включить раздел с комментариями для безопасности.