xref: /haiku/src/tests/system/kernel/set_area_protection_test1.cpp (revision e5c9c9e371e0c96d0a50bdde17fc88b9735d0690)
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 
10 int
test_function()11 test_function()
12 {
13 	return 0;
14 }
15 
16 
17 static area_id
create_test_area(const char * name,int ** address,uint32 protection)18 create_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 
32 static area_id
clone_test_area(const char * name,int ** address,uint32 protection,area_id source)33 clone_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 
48 int
main()49 main()
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