mirror of
https://github.com/rui314/mold.git
synced 2024-10-26 13:10:46 +03:00
Obtain a file lock with flock() while creating a separate debug file
This commit is contained in:
parent
315dfd3244
commit
8c1b25b3aa
@ -795,6 +795,14 @@ private:
|
|||||||
int perm;
|
int perm;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Context>
|
||||||
|
class LockingOutputFile : public OutputFile<Context> {
|
||||||
|
public:
|
||||||
|
LockingOutputFile(Context &ctx, std::string path, int perm);
|
||||||
|
void resize(Context &ctx, i64 filesize);
|
||||||
|
void close(Context &ctx) override;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// hyperloglog.cc
|
// hyperloglog.cc
|
||||||
//
|
//
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <sys/file.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -143,4 +144,52 @@ OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, int perm
|
|||||||
return std::unique_ptr<OutputFile>(file);
|
return std::unique_ptr<OutputFile>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LockingOutputFile is similar to MemoryMappedOutputFile, but it doesn't
|
||||||
|
// rename output files and instead acquires file lock using flock().
|
||||||
|
template <typename Context>
|
||||||
|
LockingOutputFile<Context>::LockingOutputFile(Context &ctx, std::string path,
|
||||||
|
int perm)
|
||||||
|
: OutputFile<Context>(path, 0, true) {
|
||||||
|
this->fd = ::open(path.c_str(), O_RDWR | O_CREAT, perm);
|
||||||
|
if (this->fd == -1)
|
||||||
|
Fatal(ctx) << "cannot open " << path << ": " << errno_string();
|
||||||
|
flock(this->fd, LOCK_EX);
|
||||||
|
|
||||||
|
// We may be overwriting to an existing debug info file. We want to
|
||||||
|
// make the file unusable so that gdb won't use it by accident until
|
||||||
|
// it's ready.
|
||||||
|
u8 buf[256] = {};
|
||||||
|
(void)!!write(this->fd, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Context>
|
||||||
|
void LockingOutputFile<Context>::resize(Context &ctx, i64 filesize) {
|
||||||
|
if (ftruncate(this->fd, filesize) == -1)
|
||||||
|
Fatal(ctx) << "ftruncate failed: " << errno_string();
|
||||||
|
|
||||||
|
this->buf = (u8 *)mmap(nullptr, filesize, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, this->fd, 0);
|
||||||
|
if (this->buf == MAP_FAILED)
|
||||||
|
Fatal(ctx) << this->path << ": mmap failed: " << errno_string();
|
||||||
|
|
||||||
|
this->filesize = filesize;
|
||||||
|
mold::output_buffer_start = this->buf;
|
||||||
|
mold::output_buffer_end = this->buf + filesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Context>
|
||||||
|
void LockingOutputFile<Context>::close(Context &ctx) {
|
||||||
|
if (!this->is_unmapped)
|
||||||
|
munmap(this->buf, this->filesize);
|
||||||
|
|
||||||
|
if (!this->buf2.empty()) {
|
||||||
|
FILE *out = fdopen(this->fd, "w");
|
||||||
|
fseek(out, 0, SEEK_END);
|
||||||
|
fwrite(&this->buf2[0], this->buf2.size(), 1, out);
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
::close(this->fd);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mold
|
} // namespace mold
|
||||||
|
@ -97,4 +97,17 @@ OutputFile<Context>::open(Context &ctx, std::string path, i64 filesize, int perm
|
|||||||
return std::unique_ptr<OutputFile<Context>>(file);
|
return std::unique_ptr<OutputFile<Context>>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Context>
|
||||||
|
LockingOutputFile<Context>::LockingOutputFile(Context &ctx, std::string path,
|
||||||
|
int perm)
|
||||||
|
: OutputFile<Context>(path, 0, true) {
|
||||||
|
Fatal(ctx) << "LockingOutputFile is not supported on Windows";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Context>
|
||||||
|
void LockingOutputFile<Context>::resize(Context &ctx, i64 filesize) {}
|
||||||
|
|
||||||
|
template <typename Context>
|
||||||
|
void LockingOutputFile<Context>::close(Context &ctx) {}
|
||||||
|
|
||||||
} // namespace mold
|
} // namespace mold
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "mold.h"
|
#include "mold.h"
|
||||||
#include "blake3.h"
|
#include "blake3.h"
|
||||||
|
#include "../common/output-file.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -3056,6 +3057,10 @@ template <typename E>
|
|||||||
void write_separate_debug_file(Context<E> &ctx) {
|
void write_separate_debug_file(Context<E> &ctx) {
|
||||||
Timer t(ctx, "write_separate_debug_file");
|
Timer t(ctx, "write_separate_debug_file");
|
||||||
|
|
||||||
|
// Open an output file early
|
||||||
|
LockingOutputFile<Context<E>> *file =
|
||||||
|
new LockingOutputFile<Context<E>>(ctx, ctx.arg.separate_debug_file, 0666);
|
||||||
|
|
||||||
// We want to write to the debug info file in background so that the
|
// We want to write to the debug info file in background so that the
|
||||||
// user doesn't have to wait for it to complete.
|
// user doesn't have to wait for it to complete.
|
||||||
if (ctx.arg.detach)
|
if (ctx.arg.detach)
|
||||||
@ -3087,11 +3092,9 @@ void write_separate_debug_file(Context<E> &ctx) {
|
|||||||
|
|
||||||
// Write to the debug info file as if it were a regular output file.
|
// Write to the debug info file as if it were a regular output file.
|
||||||
compute_section_headers(ctx);
|
compute_section_headers(ctx);
|
||||||
i64 filesize = set_osec_offsets(ctx);
|
file->resize(ctx, set_osec_offsets(ctx));
|
||||||
|
|
||||||
ctx.output_file =
|
ctx.output_file.reset(file);
|
||||||
OutputFile<Context<E>>::open(ctx, ctx.arg.separate_debug_file,
|
|
||||||
filesize, 0666);
|
|
||||||
ctx.buf = ctx.output_file->buf;
|
ctx.buf = ctx.output_file->buf;
|
||||||
|
|
||||||
copy_chunks(ctx);
|
copy_chunks(ctx);
|
||||||
@ -3102,7 +3105,7 @@ void write_separate_debug_file(Context<E> &ctx) {
|
|||||||
// Reverse-compute a CRC32 value so that the CRC32 checksum embedded to
|
// Reverse-compute a CRC32 value so that the CRC32 checksum embedded to
|
||||||
// the .gnu_debuglink section in the main executable matches with the
|
// the .gnu_debuglink section in the main executable matches with the
|
||||||
// debug info file's CRC32 checksum.
|
// debug info file's CRC32 checksum.
|
||||||
u32 crc = compute_crc32(0, ctx.buf, filesize);
|
u32 crc = compute_crc32(0, ctx.buf, ctx.output_file->filesize);
|
||||||
|
|
||||||
std::vector<u8> &buf2 = ctx.output_file->buf2;
|
std::vector<u8> &buf2 = ctx.output_file->buf2;
|
||||||
if (!buf2.empty())
|
if (!buf2.empty())
|
||||||
|
@ -16,11 +16,12 @@ $CC -c -o $t/a.o $t/a.c -g
|
|||||||
$CC -B. -o $t/exe1 $t/a.o -Wl,--separate-debug-file
|
$CC -B. -o $t/exe1 $t/a.o -Wl,--separate-debug-file
|
||||||
readelf -SW $t/exe1 | grep -Fq .gnu_debuglink
|
readelf -SW $t/exe1 | grep -Fq .gnu_debuglink
|
||||||
|
|
||||||
|
flock $t/exe1 true
|
||||||
|
gdb $t/exe1 -ex 'list main' -ex 'quit' | grep -Fq printf
|
||||||
|
|
||||||
$CC -c -o $t/a.o $t/a.c -g
|
$CC -c -o $t/a.o $t/a.c -g
|
||||||
$CC -B. -o $t/exe2 $t/a.o -Wl,--separate-debug-file -Wl,--no-build-id
|
$CC -B. -o $t/exe2 $t/a.o -Wl,--separate-debug-file -Wl,--no-build-id
|
||||||
readelf -SW $t/exe2 | grep -Fq .gnu_debuglink
|
readelf -SW $t/exe2 | grep -Fq .gnu_debuglink
|
||||||
|
|
||||||
sleep 1
|
flock $t/exe2 true
|
||||||
|
|
||||||
gdb $t/exe1 -ex 'list main' -ex 'quit' | grep -Fq printf
|
|
||||||
gdb $t/exe2 -ex 'list main' -ex 'quit' | grep -Fq printf
|
gdb $t/exe2 -ex 'list main' -ex 'quit' | grep -Fq printf
|
||||||
|
Loading…
Reference in New Issue
Block a user