1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/multi_process_lock.h"
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "base/eintr_wrapper.h"
#include "base/logging.h"
class MultiProcessLockLinux : public MultiProcessLock {
public:
explicit MultiProcessLockLinux(const std::string& name)
: name_(name), fd_(-1) { }
virtual ~MultiProcessLockLinux() {
if (fd_ != -1) {
Unlock();
}
}
virtual bool TryLock() {
if (fd_ != -1) {
DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
return true;
}
if (name_.length() > MULTI_PROCESS_LOCK_NAME_MAX_LEN) {
LOG(ERROR) << "Socket name too long (" << name_.length()
<< " > " << MULTI_PROCESS_LOCK_NAME_MAX_LEN << ") - " << name_;
return false;
}
struct sockaddr_un address;
// +1 for terminator, +1 for 0 in position 0 that makes it an
// abstract named socket.
// If this assert fails it is because sockaddr_un.sun_path size has been
// redefined and MULTI_PROCESS_LOCK_NAME_MAX_LEN can change accordingly.
COMPILE_ASSERT(sizeof(address.sun_path)
== MULTI_PROCESS_LOCK_NAME_MAX_LEN + 2, sun_path_size_changed);
memset(&address, 0, sizeof(address));
int print_length = snprintf(&address.sun_path[1],
MULTI_PROCESS_LOCK_NAME_MAX_LEN + 1,
"%s", name_.c_str());
if (print_length < 0 ||
print_length > static_cast<int>(MULTI_PROCESS_LOCK_NAME_MAX_LEN)) {
PLOG(ERROR) << "Couldn't create sun_path - " << name_;
return false;
}
// Must set the first character of the path to something non-zero
// before we call SUN_LEN which depends on strcpy working.
address.sun_path[0] = '@';
size_t length = SUN_LEN(&address);
// Reset the first character of the path back to zero so that
// bind returns an abstract name socket.
address.sun_path[0] = 0;
address.sun_family = AF_LOCAL;
int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (socket_fd < 0) {
PLOG(ERROR) << "Couldn't create socket - " << name_;
return false;
}
if (bind(socket_fd,
reinterpret_cast<sockaddr *>(&address),
length) == 0) {
fd_ = socket_fd;
return true;
} else {
PLOG(ERROR) << "Couldn't bind socket - "
<< &(address.sun_path[1])
<< " Length: " << length;
if (HANDLE_EINTR(close(socket_fd)) < 0) {
PLOG(ERROR) << "close";
}
return false;
}
}
virtual void Unlock() {
if (fd_ == -1) {
DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
return;
}
if (HANDLE_EINTR(close(fd_)) < 0) {
PLOG(ERROR) << "close";
}
fd_ = -1;
}
private:
std::string name_;
int fd_;
DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
};
MultiProcessLock* MultiProcessLock::Create(const std::string &name) {
return new MultiProcessLockLinux(name);
}
|