9
9
#include " FifoFiles.h"
10
10
#include " JSONUtils.h"
11
11
12
- #if !defined(_WIN32)
12
+ #include " llvm/Support/FileSystem.h"
13
+
14
+ #if defined(_WIN32)
15
+ #include < Windows.h>
16
+ #include < fcntl.h>
17
+ #include < io.h>
18
+ #else
13
19
#include < sys/stat.h>
14
20
#include < sys/types.h>
15
21
#include < unistd.h>
@@ -24,41 +30,94 @@ using namespace llvm;
24
30
25
31
namespace lldb_dap {
26
32
27
- FifoFile::FifoFile (StringRef path) : m_path(path) {}
33
+ std::error_code EC;
28
34
35
+ FifoFile::FifoFile (StringRef path)
36
+ : m_path(path), m_file(fopen(path.data(), " r+" )) {
37
+ if (m_file == nullptr ) {
38
+ EC = std::error_code (errno, std::generic_category ());
39
+ llvm::errs () << " Failed to open fifo file: " << path << EC.message ()
40
+ << " \n " ;
41
+ std::terminate ();
42
+ }
43
+ if (setvbuf (m_file, NULL , _IONBF, 0 ))
44
+ llvm::errs () << " Error setting unbuffered mode on C FILE\n " ;
45
+ }
46
+ FifoFile::FifoFile (StringRef path, FILE *f) : m_path(path), m_file(f) {}
47
+ FifoFile::FifoFile (FifoFile &&other)
48
+ : m_path(other.m_path), m_file(other.m_file) {
49
+ other.m_file = nullptr ;
50
+ }
29
51
FifoFile::~FifoFile () {
52
+ if (m_file)
53
+ fclose (m_file);
30
54
#if !defined(_WIN32)
55
+ // Unreferenced named pipes are deleted automatically on Win32
31
56
unlink (m_path.c_str ());
32
57
#endif
33
58
}
34
59
35
- Expected<std::shared_ptr<FifoFile>> CreateFifoFile (StringRef path) {
36
- #if defined(_WIN32)
37
- return createStringError (inconvertibleErrorCode (), " Unimplemented" );
60
+ // This probably belongs to llvm::sys::fs as another FSEntity type
61
+ std::error_code createNamedPipe (const Twine &Prefix, StringRef Suffix,
62
+ int &ResultFd,
63
+ SmallVectorImpl<char > &ResultPath) {
64
+ const char *Middle = Suffix.empty () ? " -%%%%%%" : " -%%%%%%." ;
65
+ auto EC = sys::fs::getPotentiallyUniqueFileName (
66
+ #ifdef _WIN32
67
+ " \\\\ .\\ pipe\\ LOCAL\\ "
68
+ #else
69
+ " /tmp/"
70
+ #endif
71
+ + Prefix + Middle + Suffix,
72
+ ResultPath);
73
+ if (EC)
74
+ return EC;
75
+ ResultPath.push_back (0 );
76
+ const char *path = ResultPath.data ();
77
+ #ifdef _WIN32
78
+ HANDLE h = ::CreateNamedPipeA (
79
+ path, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
80
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1 , 1024 , 1024 , 0 , NULL );
81
+ if (h == INVALID_HANDLE_VALUE)
82
+ return std::error_code (::GetLastError (), std::system_category ());
83
+ ResultFd = _open_osfhandle ((intptr_t )h, _O_TEXT | _O_RDWR);
84
+ if (ResultFd == -1 )
85
+ return std::error_code (::GetLastError (), std::system_category ());
38
86
#else
39
- if (int err = mkfifo (path.data (), 0600 ))
40
- return createStringError (std::error_code (err, std::generic_category ()),
41
- " Couldn't create fifo file: %s" , path.data ());
42
- return std::make_shared<FifoFile>(path);
87
+ if (mkfifo (path, 0600 ) == -1 )
88
+ return std::error_code (errno, std::generic_category ());
89
+ EC = openFileForWrite (ResultPath, ResultFd, sys::fs::CD_OpenExisting,
90
+ sys::fs::OF_None, 0600 );
91
+ if (EC)
92
+ return EC;
43
93
#endif
94
+ return std::error_code ();
44
95
}
45
96
46
- FifoFileIO::FifoFileIO (StringRef fifo_file, StringRef other_endpoint_name)
47
- : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {}
97
+ FifoFileIO::FifoFileIO (FifoFile &&fifo_file, StringRef other_endpoint_name)
98
+ : m_fifo_file(std::move(fifo_file)),
99
+ m_other_endpoint_name (other_endpoint_name) {}
48
100
49
101
Expected<json::Value> FifoFileIO::ReadJSON (std::chrono::milliseconds timeout) {
50
102
// We use a pointer for this future, because otherwise its normal destructor
51
103
// would wait for the getline to end, rendering the timeout useless.
52
104
std::optional<std::string> line;
53
105
std::future<void > *future =
54
106
new std::future<void >(std::async (std::launch::async, [&]() {
55
- std::ifstream reader (m_fifo_file, std::ifstream::in);
56
- std::string buffer;
57
- std::getline (reader, buffer);
58
- if (!buffer.empty ())
59
- line = buffer;
107
+ rewind (m_fifo_file.m_file );
108
+ constexpr size_t buffer_size = 2048 ;
109
+ char buffer[buffer_size];
110
+ char *ptr = fgets (buffer, buffer_size, m_fifo_file.m_file );
111
+ if (ptr == nullptr || *ptr == 0 )
112
+ return ;
113
+ size_t len = strlen (buffer);
114
+ if (len <= 1 )
115
+ return ;
116
+ buffer[len - 1 ] = ' \0 ' ; // remove newline
117
+ line = buffer;
60
118
}));
61
- if (future->wait_for (timeout) == std::future_status::timeout || !line)
119
+
120
+ if (future->wait_for (timeout) == std::future_status::timeout)
62
121
// Indeed this is a leak, but it's intentional. "future" obj destructor
63
122
// will block on waiting for the worker thread to join. And the worker
64
123
// thread might be stuck in blocking I/O. Intentionally leaking the obj
@@ -69,6 +128,11 @@ Expected<json::Value> FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) {
69
128
return createStringError (inconvertibleErrorCode (),
70
129
" Timed out trying to get messages from the " +
71
130
m_other_endpoint_name);
131
+ if (!line) {
132
+ return createStringError (inconvertibleErrorCode (),
133
+ " Failed to get messages from the " +
134
+ m_other_endpoint_name);
135
+ }
72
136
delete future;
73
137
return json::parse (*line);
74
138
}
@@ -78,8 +142,12 @@ Error FifoFileIO::SendJSON(const json::Value &json,
78
142
bool done = false ;
79
143
std::future<void > *future =
80
144
new std::future<void >(std::async (std::launch::async, [&]() {
81
- std::ofstream writer (m_fifo_file, std::ofstream::out);
82
- writer << JSONToString (json) << std::endl;
145
+ rewind (m_fifo_file.m_file );
146
+ auto payload = JSONToString (json);
147
+ if (fputs (payload.c_str (), m_fifo_file.m_file ) == EOF ||
148
+ fputc (' \n ' , m_fifo_file.m_file ) == EOF) {
149
+ return ;
150
+ }
83
151
done = true ;
84
152
}));
85
153
if (future->wait_for (timeout) == std::future_status::timeout || !done) {
@@ -98,4 +166,19 @@ Error FifoFileIO::SendJSON(const json::Value &json,
98
166
return Error::success ();
99
167
}
100
168
169
+ Error FifoFileIO::WaitForPeer () {
170
+ #ifdef _WIN32
171
+ llvm::errs () << m_fifo_file.m_file << " ; " << fileno (m_fifo_file.m_file )
172
+ << " \n " ;
173
+ if (!::ConnectNamedPipe ((HANDLE)_get_osfhandle (fileno (m_fifo_file.m_file )),
174
+ NULL ) &&
175
+ GetLastError () != ERROR_PIPE_CONNECTED) {
176
+ return createStringError (
177
+ std::error_code (GetLastError (), std::system_category ()),
178
+ " Failed to connect to the " + m_other_endpoint_name);
179
+ }
180
+ #endif
181
+ return Error::success ();
182
+ }
183
+
101
184
} // namespace lldb_dap
0 commit comments