1#include <errno.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6
7#include <OS.h>
8
9
10int
11test_function()
12{
13	return 0;
14}
15
16
17static area_id
18create_test_area(const char* name, int** address, uint32 protection)
19{
20	area_id area = create_area(name, (void**)address, B_ANY_ADDRESS,
21		B_PAGE_SIZE, B_NO_LOCK, protection);
22	if (area < 0) {
23		fprintf(stderr, "Error: Failed to create area %s: %s\n", name,
24			strerror(area));
25		exit(1);
26	}
27
28	return area;
29}
30
31
32static area_id
33clone_test_area(const char* name, int** address, uint32 protection,
34	area_id source)
35{
36	area_id area = clone_area(name, (void**)address, B_ANY_ADDRESS,
37		protection, source);
38	if (area < 0) {
39		fprintf(stderr, "Error: Failed to clone area %s: %s\n", name,
40			strerror(area));
41		exit(1);
42	}
43
44	return area;
45}
46
47
48int
49main()
50{
51	// allocate read-only areas
52	const int kAreaCount = 4;
53	area_id areas[kAreaCount];
54	int* areaAddresses[kAreaCount];
55
56	areas[0] = create_test_area("area0", &areaAddresses[0], B_READ_AREA);
57	areas[1] = create_test_area("area1", &areaAddresses[1], B_READ_AREA);
58	areas[2] = create_test_area("area2", &areaAddresses[2], B_READ_AREA);
59	areaAddresses[3] = (int*)test_function;
60	areas[3] = area_for(areaAddresses[3]);
61
62	int* area2CloneAddress;
63	/*area_id area2Clone =*/ clone_test_area("area2clone", &area2CloneAddress,
64		B_READ_AREA | B_WRITE_AREA, areas[2]);
65
66	int area3Value = *areaAddresses[3];
67
68	for (int i = 0; i < kAreaCount; i++) {
69		printf("parent: areas[%d]: %ld, %p (0x%08x)\n", i, areas[i],
70			areaAddresses[i], *areaAddresses[i]);
71	}
72
73	// fork()
74	pid_t pid = fork();
75	if (pid < 0) {
76		fprintf(stderr, "Error: Failed to fork(): %s\n", strerror(errno));
77		exit(1);
78	}
79
80	if (pid == 0) {
81		// child
82		pid = find_thread(NULL);
83
84		int expectedValues[kAreaCount] = {
85			0,				// CoW -- the child should see the original value
86			pid,			// clone -- the child should see the change
87			pid,			// clone -- the child should see the change
88			area3Value		// CoW -- the child should see the original value
89							// Note: It looks alright in BeOS in the first run,
90							// but the parent actually seems to modify some
91							// cached page, and in the next run, we'll see
92							// the changed value.
93		};
94
95		// get the IDs of the copied areas
96		area_id parentAreas[kAreaCount];
97		for (int i = 0; i < kAreaCount; i++) {
98			parentAreas[i] = areas[i];
99			areas[i] = area_for(areaAddresses[i]);
100		}
101
102		for (int i = 0; i < kAreaCount; i++) {
103			printf("child: areas[%d]: %ld, %p\n", i, areas[i],
104				areaAddresses[i]);
105		}
106
107		// clone area 1
108		delete_area(areas[1]);
109		areas[1] = clone_test_area("child:area1", &areaAddresses[1],
110			B_READ_AREA, parentAreas[1]);
111
112		// clone area 2
113		delete_area(areas[2]);
114		areas[2] = clone_test_area("child:area2", &areaAddresses[2],
115			B_READ_AREA, parentAreas[2]);
116
117		snooze(400000);
118
119		for (int i = 0; i < kAreaCount; i++) {
120			printf("child: area[%d] contains: 0x%08x (expected: 0x%08x)\n", i,
121				*areaAddresses[i], expectedValues[i]);
122		}
123
124	} else {
125		// parent
126
127		snooze(200000);
128
129		for (int i = 0; i < kAreaCount; i++) {
130			status_t error = set_area_protection(areas[i],
131				B_READ_AREA | B_WRITE_AREA);
132			if (error == B_OK) {
133				*areaAddresses[i] = pid;
134			} else {
135				fprintf(stderr, "parent: Error: set_area_protection(areas[%d]) "
136					"failed: %s\n", i, strerror(error));
137			}
138		}
139
140		status_t result;
141		wait_for_thread(pid, &result);
142	}
143
144	return 0;
145}
146