fd = open(filename, O_RDWR | O_BINARY);
if (fd == -1) {
- /* Try opening the file, creating it if necessary. */
- new_file = 1;
- mode = "w+b";
- fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
- if (fd == -1) {
+ /* Try creating the file. */
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644);
+ if (fd != -1) {
+ new_file = 1;
+ mode = "w+b";
+ } else {
/* Try creating the directories first then opening the file. */
__llvm_profile_recursive_mkdir(filename);
- fd = open(filename, O_RDWR | O_CREAT | O_BINARY, 0644);
- if (fd == -1) {
- /* Bah! It's hopeless. */
- int errnum = errno;
- fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
- strerror(errnum));
- return;
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0644);
+ if (fd != -1) {
+ new_file = 1;
+ mode = "w+b";
+ } else {
+ /* Another process may have created the file just now.
+ * Try opening it without O_CREAT and O_EXCL. */
+ fd = open(filename, O_RDWR | O_BINARY);
+ if (fd == -1) {
+ /* Bah! It's hopeless. */
+ int errnum = errno;
+ fprintf(stderr, "profiling: %s: cannot open: %s\n", filename,
+ strerror(errnum));
+ return;
+ }
}
}
}
--- /dev/null
+#include <stdatomic.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define CHILDREN 7
+
+int main(int argc, char *argv[]) {
+ _Atomic int *sync = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (sync == MAP_FAILED)
+ return 1;
+ *sync = 0;
+
+ for (int i = 0; i < CHILDREN; i++) {
+ pid_t pid = fork();
+ if (!pid) {
+ // child
+ while (*sync == 0)
+ ; // wait the parent in order to call execl simultaneously
+ execl(argv[1], argv[1], NULL);
+ } else if (pid == -1) {
+ *sync = 1; // release all children
+ return 1;
+ }
+ }
+
+ // parent
+ *sync = 1; // start the program in all children simultaneously
+ for (int i = 0; i < CHILDREN; i++)
+ wait(NULL);
+
+ return 0;
+}
--- /dev/null
+#define COUNT 101
+
+static volatile int aaa;
+
+int main(int argc, char *argv[]) {
+ for (int i = 0; i < COUNT; i++)
+ aaa++;
+ return 0;
+}
--- /dev/null
+RUN: mkdir -p %t.d
+RUN: cd %t.d
+
+RUN: %clang -o %t.driver %S/../Inputs/instrprof-gcov-parallel.driver.c
+RUN: %clang --coverage -o %t.target %S/../Inputs/instrprof-gcov-parallel.target.c
+RUN: test -f instrprof-gcov-parallel.target.gcno
+
+RUN: rm -f instrprof-gcov-parallel.target.gcda
+RUN: %run %t.driver %t.target
+RUN: llvm-cov gcov instrprof-gcov-parallel.target.gcda
+RUN: FileCheck --input-file instrprof-gcov-parallel.target.c.gcov %s
+
+# Test if the .gcda file is correctly created from one of child processes
+# and counters of all processes are recorded correctly.
+# 707 = CHILDREN * COUNT
+CHECK: 707: {{[0-9]+}}: aaa++;