Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use VirtualProtect to mark pages as copy-on-write (poor-man's fork on windows)

Tags:

c++

c#

fork

windows

I use VirtualAlloc(Ex) to allocate and commit a large range of pages.

Later in the execution I wish to "fork" that memory, launch a new process that can read it in it's current state, while the parent process treats it as copy-on-write memory.

Can this be done with VirtualAlloc(Ex) and VirtualProtect(Ex)?

This is trivial on posix systems thanks to fork(). Can I emulate just this part of fork efficiently on windows?

Thanks, -Dan

like image 446
Eloff Avatar asked Feb 27 '11 16:02

Eloff


2 Answers

I don't believe any of these quite answer the question posed by the original poster. Perhaps I might venture the following example. Suppose one has some data in "bufferA" and one copies it to "bufferB" and then modifies both buffers. Now one examines both buffers, and decides to copy either "bufferA" or "bufferB" to "bufferC" and make more modifications to "bufferC", and so forth.

Assuming that the buffers are large and the modifications are small, the question is whether it would be an optimization to use the copy-on-write capability of the MMU on the host machine, and whether there is an API to allow this.

The use of memory mapped files doesn't quite work because, once one uses PAGE_WRITECOPY, there seems to be no way to say "now copy the virtual pages containing the changes". For example, if "bufferA" and "bufferB" both were mappings of the same file, and at the time of the mapping one of them was marked "WRITECOPY", there seems to be no way to map those modifications to "bufferC". One can of course just copy the bits, but the question is whether there is a potential optimization.

There is a function called VirtualCopy(), but that seems to be Windows CE specific, and works with physical addresses. The question here is whether there is something like "VirtualCopy", but taking a virtual address as the source.

Note that while "fork()" (on systems which have it) does this, one "fork's" the whole process, not just the buffer. There was a related discussion regarding "copy-on-write memcpy" here ( Can I do a copy-on-write memcpy in Linux? ).

So the API being sought might look something like this: void * VirualCopyVirtualAddressSpace( void* src, size_t length);

So far, I have seen no API on any system which would allow the buffers to be copied either within a process or between existing processes. While I'm not an expert, I would have thought that copying a properly aligned segment of virtual memory via the copy-on-write mechanism would have be reasonably simple, at least within a single address space.

like image 80
Mike Albert Avatar answered Sep 28 '22 14:09

Mike Albert


I think you can do that if you use memory mapping (CreateFileMapping/MapViewOfFile) with PAGE_WRITECOPY.

This example in MSDN might serve as starting point, if you change FILE_MAP_ALL_ACCESS to PAGE_WRITECOPY for the second process.

If you want a consistent point-of-time copy behavior, you'll likely need to VirtualProtect() the mapped region with PAGE_WRITECOPY in the first process, so second process does not see any changes.

like image 30
Vladislav Vaintroub Avatar answered Sep 28 '22 13:09

Vladislav Vaintroub