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 11 test_function() 12 { 13 return 0; 14 } 15 16 17 static area_id 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 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 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