@@ -1025,6 +1025,195 @@ int main()
1025
1025
}" HAVE_FULLY_FEATURED_PTHREAD_MUTEXES)
1026
1026
set (CMAKE_REQUIRED_LIBRARIES)
1027
1027
1028
+ if (NOT CLR_CMAKE_PLATFORM_ARCH_ARM AND NOT CLR_CMAKE_PLATFORM_ARCH_ARM64)
1029
+ set (CMAKE_REQUIRED_LIBRARIES pthread)
1030
+ check_cxx_source_runs("
1031
+ // This test case verifies the pthread process-shared robust mutex's cross-process abandon detection. The parent process starts
1032
+ // a child process that locks the mutex, the process process then waits to acquire the lock, and the child process abandons the
1033
+ // mutex by exiting the process while holding the lock. The parent process should then be released from its wait, be assigned
1034
+ // ownership of the lock, and be notified that the mutex was abandoned.
1035
+
1036
+ #include <sys/mman.h>
1037
+ #include <sys/time.h>
1038
+
1039
+ #include <errno.h>
1040
+ #include <pthread.h>
1041
+ #include <stdio.h>
1042
+ #include <unistd.h>
1043
+
1044
+ #include <new>
1045
+ using namespace std;
1046
+
1047
+ struct Shm
1048
+ {
1049
+ pthread_mutex_t syncMutex;
1050
+ pthread_cond_t syncCondition;
1051
+ pthread_mutex_t robustMutex;
1052
+ int conditionValue;
1053
+
1054
+ Shm() : conditionValue(0)
1055
+ {
1056
+ }
1057
+ } *shm;
1058
+
1059
+ int GetFailTimeoutTime(struct timespec *timeoutTimeRef)
1060
+ {
1061
+ int getTimeResult = clock_gettime(CLOCK_REALTIME, timeoutTimeRef);
1062
+ if (getTimeResult != 0)
1063
+ {
1064
+ struct timeval tv;
1065
+ getTimeResult = gettimeofday(&tv, NULL);
1066
+ if (getTimeResult != 0)
1067
+ return 1;
1068
+ timeoutTimeRef->tv_sec = tv.tv_sec;
1069
+ timeoutTimeRef->tv_nsec = tv.tv_usec * 1000;
1070
+ }
1071
+ timeoutTimeRef->tv_sec += 30;
1072
+ return 0;
1073
+ }
1074
+
1075
+ int WaitForConditionValue(int desiredConditionValue)
1076
+ {
1077
+ struct timespec timeoutTime;
1078
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
1079
+ return 1;
1080
+ if (pthread_mutex_timedlock(&shm->syncMutex, &timeoutTime) != 0)
1081
+ return 1;
1082
+
1083
+ if (shm->conditionValue != desiredConditionValue)
1084
+ {
1085
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
1086
+ return 1;
1087
+ if (pthread_cond_timedwait(&shm->syncCondition, &shm->syncMutex, &timeoutTime) != 0)
1088
+ return 1;
1089
+ if (shm->conditionValue != desiredConditionValue)
1090
+ return 1;
1091
+ }
1092
+
1093
+ if (pthread_mutex_unlock(&shm->syncMutex) != 0)
1094
+ return 1;
1095
+ return 0;
1096
+ }
1097
+
1098
+ int SetConditionValue(int newConditionValue)
1099
+ {
1100
+ struct timespec timeoutTime;
1101
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
1102
+ return 1;
1103
+ if (pthread_mutex_timedlock(&shm->syncMutex, &timeoutTime) != 0)
1104
+ return 1;
1105
+
1106
+ shm->conditionValue = newConditionValue;
1107
+ if (pthread_cond_signal(&shm->syncCondition) != 0)
1108
+ return 1;
1109
+
1110
+ if (pthread_mutex_unlock(&shm->syncMutex) != 0)
1111
+ return 1;
1112
+ return 0;
1113
+ }
1114
+
1115
+ void DoTest_Child();
1116
+
1117
+ int DoTest()
1118
+ {
1119
+ // Map some shared memory
1120
+ void *shmBuffer = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
1121
+ if (shmBuffer == MAP_FAILED)
1122
+ return 1;
1123
+ shm = new(shmBuffer) Shm;
1124
+
1125
+ // Create sync mutex
1126
+ pthread_mutexattr_t syncMutexAttributes;
1127
+ if (pthread_mutexattr_init(&syncMutexAttributes) != 0)
1128
+ return 1;
1129
+ if (pthread_mutexattr_setpshared(&syncMutexAttributes, PTHREAD_PROCESS_SHARED) != 0)
1130
+ return 1;
1131
+ if (pthread_mutex_init(&shm->syncMutex, &syncMutexAttributes) != 0)
1132
+ return 1;
1133
+ if (pthread_mutexattr_destroy(&syncMutexAttributes) != 0)
1134
+ return 1;
1135
+
1136
+ // Create sync condition
1137
+ pthread_condattr_t syncConditionAttributes;
1138
+ if (pthread_condattr_init(&syncConditionAttributes) != 0)
1139
+ return 1;
1140
+ if (pthread_condattr_setpshared(&syncConditionAttributes, PTHREAD_PROCESS_SHARED) != 0)
1141
+ return 1;
1142
+ if (pthread_cond_init(&shm->syncCondition, &syncConditionAttributes) != 0)
1143
+ return 1;
1144
+ if (pthread_condattr_destroy(&syncConditionAttributes) != 0)
1145
+ return 1;
1146
+
1147
+ // Create the robust mutex that will be tested
1148
+ pthread_mutexattr_t robustMutexAttributes;
1149
+ if (pthread_mutexattr_init(&robustMutexAttributes) != 0)
1150
+ return 1;
1151
+ if (pthread_mutexattr_setpshared(&robustMutexAttributes, PTHREAD_PROCESS_SHARED) != 0)
1152
+ return 1;
1153
+ if (pthread_mutexattr_setrobust(&robustMutexAttributes, PTHREAD_MUTEX_ROBUST) != 0)
1154
+ return 1;
1155
+ if (pthread_mutex_init(&shm->robustMutex, &robustMutexAttributes) != 0)
1156
+ return 1;
1157
+ if (pthread_mutexattr_destroy(&robustMutexAttributes) != 0)
1158
+ return 1;
1159
+
1160
+ // Start child test process
1161
+ int error = fork();
1162
+ if (error == -1)
1163
+ return 1;
1164
+ if (error == 0)
1165
+ {
1166
+ DoTest_Child();
1167
+ return -1;
1168
+ }
1169
+
1170
+ // Wait for child to take a lock
1171
+ WaitForConditionValue(1);
1172
+
1173
+ // Wait to try to take a lock. Meanwhile, child abandons the robust mutex.
1174
+ struct timespec timeoutTime;
1175
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
1176
+ return 1;
1177
+ error = pthread_mutex_timedlock(&shm->robustMutex, &timeoutTime);
1178
+ if (error != EOWNERDEAD) // expect to be notified that the robust mutex was abandoned
1179
+ return 1;
1180
+ if (pthread_mutex_consistent(&shm->robustMutex) != 0)
1181
+ return 1;
1182
+
1183
+ if (pthread_mutex_unlock(&shm->robustMutex) != 0)
1184
+ return 1;
1185
+ if (pthread_mutex_destroy(&shm->robustMutex) != 0)
1186
+ return 1;
1187
+ return 0;
1188
+ }
1189
+
1190
+ void DoTest_Child()
1191
+ {
1192
+ // Lock the robust mutex
1193
+ struct timespec timeoutTime;
1194
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
1195
+ return;
1196
+ if (pthread_mutex_timedlock(&shm->robustMutex, &timeoutTime) != 0)
1197
+ return;
1198
+
1199
+ // Notify parent that robust mutex is locked
1200
+ if (SetConditionValue(1) != 0)
1201
+ return;
1202
+
1203
+ // Wait a short period to let the parent block on waiting for a lock
1204
+ sleep(1);
1205
+
1206
+ // Abandon the mutex by exiting the process while holding the lock. Parent's wait should be released by EOWNERDEAD.
1207
+ }
1208
+
1209
+ int main()
1210
+ {
1211
+ int result = DoTest();
1212
+ return result >= 0 ? result : 0;
1213
+ }" HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES)
1214
+ set (CMAKE_REQUIRED_LIBRARIES)
1215
+ endif ()
1216
+
1028
1217
if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
1029
1218
if (NOT HAVE_LIBUUID_H)
1030
1219
unset (HAVE_LIBUUID_H CACHE )
0 commit comments