1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #ifndef TENSORFLOW_CORE_PLATFORM_ENV_H_
17 #define TENSORFLOW_CORE_PLATFORM_ENV_H_
18
19 #include <stdint.h>
20
21 #include <memory>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25
26 #include "tensorflow/core/platform/env_time.h"
27 #include "tensorflow/core/platform/errors.h"
28 #include "tensorflow/core/platform/file_system.h"
29 #include "tensorflow/core/platform/macros.h"
30 #include "tensorflow/core/platform/mutex.h"
31 #include "tensorflow/core/platform/numa.h"
32 #include "tensorflow/core/platform/platform.h"
33 #include "tensorflow/core/platform/protobuf.h"
34 #include "tensorflow/core/platform/status.h"
35 #include "tensorflow/core/platform/stringpiece.h"
36 #include "tensorflow/core/platform/types.h"
37
38 // Delete the definition of CopyFile as the linker gets confused.
39 #ifdef PLATFORM_WINDOWS
40 #undef CopyFile
41 #endif
42
43 namespace tensorflow {
44
45 class Thread;
46 struct ThreadOptions;
47
48 /// \brief An interface used by the tensorflow implementation to
49 /// access operating system functionality like the filesystem etc.
50 ///
51 /// Callers may wish to provide a custom Env object to get fine grain
52 /// control.
53 ///
54 /// All Env implementations are safe for concurrent access from
55 /// multiple threads without any external synchronization.
56 class Env {
57 public:
58 Env();
59 virtual ~Env() = default;
60
61 /// \brief Returns a default environment suitable for the current operating
62 /// system.
63 ///
64 /// Sophisticated users may wish to provide their own Env
65 /// implementation instead of relying on this default environment.
66 ///
67 /// The result of Default() belongs to this library and must never be deleted.
68 static Env* Default();
69
70 /// \brief Returns the FileSystem object to handle operations on the file
71 /// specified by 'fname'. The FileSystem object is used as the implementation
72 /// for the file system related (non-virtual) functions that follow.
73 /// Returned FileSystem object is still owned by the Env object and will
74 // (might) be destroyed when the environment is destroyed.
75 virtual Status GetFileSystemForFile(const std::string& fname,
76 FileSystem** result);
77
78 /// \brief Returns the file system schemes registered for this Env.
79 virtual Status GetRegisteredFileSystemSchemes(
80 std::vector<std::string>* schemes);
81
82 /// \brief Register a file system for a scheme.
83 virtual Status RegisterFileSystem(const std::string& scheme,
84 FileSystemRegistry::Factory factory);
85
86 /// \brief Register a modular file system for a scheme.
87 ///
88 /// Same as `RegisterFileSystem` but for filesystems provided by plugins.
89 ///
90 /// TODO(mihaimaruseac): After all filesystems are converted, make this be the
91 /// canonical registration function.
92 virtual Status RegisterFileSystem(const std::string& scheme,
93 std::unique_ptr<FileSystem> filesystem);
94
95 /// \brief Flush filesystem caches for all registered filesystems.
96 Status FlushFileSystemCaches();
97
98 /// \brief Creates a brand new random access read-only file with the
99 /// specified name.
100
101 /// On success, stores a pointer to the new file in
102 /// *result and returns OK. On failure stores NULL in *result and
103 /// returns non-OK. If the file does not exist, returns a non-OK
104 /// status.
105 ///
106 /// The returned file may be concurrently accessed by multiple threads.
107 ///
108 /// The ownership of the returned RandomAccessFile is passed to the caller
109 /// and the object should be deleted when is not used. The file object
110 /// shouldn't live longer than the Env object.
111 Status NewRandomAccessFile(const string& fname,
112 std::unique_ptr<RandomAccessFile>* result);
113
114 /// \brief Creates an object that writes to a new file with the specified
115 /// name.
116 ///
117 /// Deletes any existing file with the same name and creates a
118 /// new file. On success, stores a pointer to the new file in
119 /// *result and returns OK. On failure stores NULL in *result and
120 /// returns non-OK.
121 ///
122 /// The returned file will only be accessed by one thread at a time.
123 ///
124 /// The ownership of the returned WritableFile is passed to the caller
125 /// and the object should be deleted when is not used. The file object
126 /// shouldn't live longer than the Env object.
127 Status NewWritableFile(const string& fname,
128 std::unique_ptr<WritableFile>* result);
129
130 /// \brief Creates an object that either appends to an existing file, or
131 /// writes to a new file (if the file does not exist to begin with).
132 ///
133 /// On success, stores a pointer to the new file in *result and
134 /// returns OK. On failure stores NULL in *result and returns
135 /// non-OK.
136 ///
137 /// The returned file will only be accessed by one thread at a time.
138 ///
139 /// The ownership of the returned WritableFile is passed to the caller
140 /// and the object should be deleted when is not used. The file object
141 /// shouldn't live longer than the Env object.
142 Status NewAppendableFile(const string& fname,
143 std::unique_ptr<WritableFile>* result);
144
145 /// \brief Creates a readonly region of memory with the file context.
146 ///
147 /// On success, it returns a pointer to read-only memory region
148 /// from the content of file fname. The ownership of the region is passed to
149 /// the caller. On failure stores nullptr in *result and returns non-OK.
150 ///
151 /// The returned memory region can be accessed from many threads in parallel.
152 ///
153 /// The ownership of the returned ReadOnlyMemoryRegion is passed to the caller
154 /// and the object should be deleted when is not used. The memory region
155 /// object shouldn't live longer than the Env object.
156 Status NewReadOnlyMemoryRegionFromFile(
157 const string& fname, std::unique_ptr<ReadOnlyMemoryRegion>* result);
158
159 /// Returns OK if the named path exists and NOT_FOUND otherwise.
160 Status FileExists(const string& fname);
161
162 /// Returns true if all the listed files exist, false otherwise.
163 /// if status is not null, populate the vector with a detailed status
164 /// for each file.
165 bool FilesExist(const std::vector<string>& files,
166 std::vector<Status>* status);
167
168 /// \brief Stores in *result the names of the children of the specified
169 /// directory. The names are relative to "dir".
170 ///
171 /// Original contents of *results are dropped.
172 Status GetChildren(const string& dir, std::vector<string>* result);
173
174 /// \brief Returns true if the path matches the given pattern. The wildcards
175 /// allowed in pattern are described in FileSystem::GetMatchingPaths.
176 virtual bool MatchPath(const string& path, const string& pattern) = 0;
177
178 /// \brief Given a pattern, stores in *results the set of paths that matches
179 /// that pattern. *results is cleared.
180 ///
181 /// More details about `pattern` in FileSystem::GetMatchingPaths.
182 virtual Status GetMatchingPaths(const string& pattern,
183 std::vector<string>* results);
184
185 /// Deletes the named file.
186 Status DeleteFile(const string& fname);
187
188 /// \brief Deletes the specified directory and all subdirectories and files
189 /// underneath it. This is accomplished by traversing the directory tree
190 /// rooted at dirname and deleting entries as they are encountered.
191 ///
192 /// If dirname itself is not readable or does not exist, *undeleted_dir_count
193 /// is set to 1, *undeleted_file_count is set to 0 and an appropriate status
194 /// (e.g. NOT_FOUND) is returned.
195 ///
196 /// If dirname and all its descendants were successfully deleted, TF_OK is
197 /// returned and both error counters are set to zero.
198 ///
199 /// Otherwise, while traversing the tree, undeleted_file_count and
200 /// undeleted_dir_count are updated if an entry of the corresponding type
201 /// could not be deleted. The returned error status represents the reason that
202 /// any one of these entries could not be deleted.
203 ///
204 /// REQUIRES: undeleted_files, undeleted_dirs to be not null.
205 ///
206 /// Typical return codes:
207 /// * OK - dirname exists and we were able to delete everything underneath.
208 /// * NOT_FOUND - dirname doesn't exist
209 /// * PERMISSION_DENIED - dirname or some descendant is not writable
210 /// * UNIMPLEMENTED - Some underlying functions (like Delete) are not
211 /// implemented
212 Status DeleteRecursively(const string& dirname, int64* undeleted_files,
213 int64* undeleted_dirs);
214
215 /// \brief Creates the specified directory and all the necessary
216 /// subdirectories. Typical return codes.
217 /// * OK - successfully created the directory and sub directories, even if
218 /// they were already created.
219 /// * PERMISSION_DENIED - dirname or some subdirectory is not writable.
220 Status RecursivelyCreateDir(const string& dirname);
221
222 /// \brief Creates the specified directory. Typical return codes
223 /// * OK - successfully created the directory.
224 /// * ALREADY_EXISTS - directory already exists.
225 /// * PERMISSION_DENIED - dirname is not writable.
226 Status CreateDir(const string& dirname);
227
228 /// Deletes the specified directory.
229 Status DeleteDir(const string& dirname);
230
231 /// Obtains statistics for the given path.
232 Status Stat(const string& fname, FileStatistics* stat);
233
234 /// \brief Returns whether the given path is a directory or not.
235 /// Typical return codes (not guaranteed exhaustive):
236 /// * OK - The path exists and is a directory.
237 /// * FAILED_PRECONDITION - The path exists and is not a directory.
238 /// * NOT_FOUND - The path entry does not exist.
239 /// * PERMISSION_DENIED - Insufficient permissions.
240 /// * UNIMPLEMENTED - The file factory doesn't support directories.
241 Status IsDirectory(const string& fname);
242
243 /// Stores the size of `fname` in `*file_size`.
244 Status GetFileSize(const string& fname, uint64* file_size);
245
246 /// \brief Renames file src to target. If target already exists, it will be
247 /// replaced.
248 Status RenameFile(const string& src, const string& target);
249
250 /// \brief Copy the src to target.
251 Status CopyFile(const string& src, const string& target);
252
253 /// \brief Returns the absolute path of the current executable. It resolves
254 /// symlinks if there is any.
255 string GetExecutablePath();
256
257 /// Creates a local unique temporary file name. Returns true if success.
258 bool LocalTempFilename(string* filename);
259
260 /// Creates a local unique file name that starts with |prefix| and ends with
261 /// |suffix|. Returns true if success.
262 bool CreateUniqueFileName(string* prefix, const string& suffix);
263
264 /// \brief Return the runfiles directory if running under bazel. Returns
265 /// the directory the executable is located in if not running under bazel.
266 virtual string GetRunfilesDir() = 0;
267
268 // TODO(jeff,sanjay): Add back thread/thread-pool support if needed.
269 // TODO(jeff,sanjay): if needed, tighten spec so relative to epoch, or
270 // provide a routine to get the absolute time.
271
272 /// \brief Returns the number of nano-seconds since the Unix epoch.
NowNanos()273 virtual uint64 NowNanos() const { return EnvTime::NowNanos(); }
274
275 /// \brief Returns the number of micro-seconds since the Unix epoch.
NowMicros()276 virtual uint64 NowMicros() const { return EnvTime::NowMicros(); }
277
278 /// \brief Returns the number of seconds since the Unix epoch.
NowSeconds()279 virtual uint64 NowSeconds() const { return EnvTime::NowSeconds(); }
280
281 /// Sleeps/delays the thread for the prescribed number of micro-seconds.
282 virtual void SleepForMicroseconds(int64 micros) = 0;
283
284 /// \brief Returns a new thread that is running fn() and is identified
285 /// (for debugging/performance-analysis) by "name".
286 ///
287 /// Caller takes ownership of the result and must delete it eventually
288 /// (the deletion will block until fn() stops running).
289 virtual Thread* StartThread(const ThreadOptions& thread_options,
290 const string& name,
291 std::function<void()> fn) TF_MUST_USE_RESULT = 0;
292
293 // Returns the thread id of calling thread.
294 // Posix: Returns pthread id which is only guaranteed to be unique within a
295 // process.
296 // Windows: Returns thread id which is unique.
297 virtual int32 GetCurrentThreadId() = 0;
298
299 // Copies current thread name to "name". Returns true if success.
300 virtual bool GetCurrentThreadName(string* name) = 0;
301
302 // \brief Schedules the given closure on a thread-pool.
303 //
304 // NOTE(mrry): This closure may block.
305 virtual void SchedClosure(std::function<void()> closure) = 0;
306
307 // \brief Schedules the given closure on a thread-pool after the given number
308 // of microseconds.
309 //
310 // NOTE(mrry): This closure must not block.
311 virtual void SchedClosureAfter(int64 micros,
312 std::function<void()> closure) = 0;
313
314 // \brief Load a dynamic library.
315 //
316 // Pass "library_filename" to a platform-specific mechanism for dynamically
317 // loading a library. The rules for determining the exact location of the
318 // library are platform-specific and are not documented here.
319 //
320 // On success, returns a handle to the library in "*handle" and returns
321 // OK from the function.
322 // Otherwise returns nullptr in "*handle" and an error status from the
323 // function.
324 virtual Status LoadLibrary(const char* library_filename, void** handle) = 0;
325
326 // \brief Get a pointer to a symbol from a dynamic library.
327 //
328 // "handle" should be a pointer returned from a previous call to LoadLibrary.
329 // On success, store a pointer to the located symbol in "*symbol" and return
330 // OK from the function. Otherwise, returns nullptr in "*symbol" and an error
331 // status from the function.
332 virtual Status GetSymbolFromLibrary(void* handle, const char* symbol_name,
333 void** symbol) = 0;
334
335 // \brief build the name of dynamic library.
336 //
337 // "name" should be name of the library.
338 // "version" should be the version of the library or NULL
339 // returns the name that LoadLibrary() can use
340 virtual string FormatLibraryFileName(const string& name,
341 const string& version) = 0;
342
343 // Returns a possible list of local temporary directories.
344 virtual void GetLocalTempDirectories(std::vector<string>* list) = 0;
345
346 private:
347 std::unique_ptr<FileSystemRegistry> file_system_registry_;
348 TF_DISALLOW_COPY_AND_ASSIGN(Env);
349 };
350
351 /// \brief An implementation of Env that forwards all calls to another Env.
352 ///
353 /// May be useful to clients who wish to override just part of the
354 /// functionality of another Env.
355 class EnvWrapper : public Env {
356 public:
357 /// Initializes an EnvWrapper that delegates all calls to *t
EnvWrapper(Env * t)358 explicit EnvWrapper(Env* t) : target_(t) {}
359 ~EnvWrapper() override;
360
361 /// Returns the target to which this Env forwards all calls
target()362 Env* target() const { return target_; }
363
GetFileSystemForFile(const string & fname,FileSystem ** result)364 Status GetFileSystemForFile(const string& fname,
365 FileSystem** result) override {
366 return target_->GetFileSystemForFile(fname, result);
367 }
368
GetRegisteredFileSystemSchemes(std::vector<string> * schemes)369 Status GetRegisteredFileSystemSchemes(std::vector<string>* schemes) override {
370 return target_->GetRegisteredFileSystemSchemes(schemes);
371 }
372
RegisterFileSystem(const string & scheme,FileSystemRegistry::Factory factory)373 Status RegisterFileSystem(const string& scheme,
374 FileSystemRegistry::Factory factory) override {
375 return target_->RegisterFileSystem(scheme, factory);
376 }
377
MatchPath(const string & path,const string & pattern)378 bool MatchPath(const string& path, const string& pattern) override {
379 return target_->MatchPath(path, pattern);
380 }
381
NowMicros()382 uint64 NowMicros() const override { return target_->NowMicros(); }
SleepForMicroseconds(int64 micros)383 void SleepForMicroseconds(int64 micros) override {
384 target_->SleepForMicroseconds(micros);
385 }
StartThread(const ThreadOptions & thread_options,const string & name,std::function<void ()> fn)386 Thread* StartThread(const ThreadOptions& thread_options, const string& name,
387 std::function<void()> fn) override {
388 return target_->StartThread(thread_options, name, fn);
389 }
GetCurrentThreadId()390 int32 GetCurrentThreadId() override { return target_->GetCurrentThreadId(); }
GetCurrentThreadName(string * name)391 bool GetCurrentThreadName(string* name) override {
392 return target_->GetCurrentThreadName(name);
393 }
SchedClosure(std::function<void ()> closure)394 void SchedClosure(std::function<void()> closure) override {
395 target_->SchedClosure(closure);
396 }
SchedClosureAfter(int64 micros,std::function<void ()> closure)397 void SchedClosureAfter(int64 micros, std::function<void()> closure) override {
398 target_->SchedClosureAfter(micros, closure);
399 }
LoadLibrary(const char * library_filename,void ** handle)400 Status LoadLibrary(const char* library_filename, void** handle) override {
401 return target_->LoadLibrary(library_filename, handle);
402 }
GetSymbolFromLibrary(void * handle,const char * symbol_name,void ** symbol)403 Status GetSymbolFromLibrary(void* handle, const char* symbol_name,
404 void** symbol) override {
405 return target_->GetSymbolFromLibrary(handle, symbol_name, symbol);
406 }
FormatLibraryFileName(const string & name,const string & version)407 string FormatLibraryFileName(const string& name,
408 const string& version) override {
409 return target_->FormatLibraryFileName(name, version);
410 }
411
GetRunfilesDir()412 string GetRunfilesDir() override { return target_->GetRunfilesDir(); }
413
414 private:
GetLocalTempDirectories(std::vector<string> * list)415 void GetLocalTempDirectories(std::vector<string>* list) override {
416 target_->GetLocalTempDirectories(list);
417 }
418
419 Env* target_;
420 };
421
422 /// Represents a thread used to run a TensorFlow function.
423 class Thread {
424 public:
Thread()425 Thread() {}
426
427 /// Blocks until the thread of control stops running.
428 virtual ~Thread();
429
430 private:
431 TF_DISALLOW_COPY_AND_ASSIGN(Thread);
432 };
433
434 /// \brief Cross-platform setenv.
435 ///
436 /// Since setenv() is not available on windows, we provide an
437 /// alternative with platform specific implementations here.
438 int setenv(const char* name, const char* value, int overwrite);
439
440 /// Cross-platform unsetenv.
441 int unsetenv(const char* name);
442
443 /// \brief Options to configure a Thread.
444 ///
445 /// Note that the options are all hints, and the
446 /// underlying implementation may choose to ignore it.
447 struct ThreadOptions {
448 /// Thread stack size to use (in bytes).
449 size_t stack_size = 0; // 0: use system default value
450 /// Guard area size to use near thread stacks to use (in bytes)
451 size_t guard_size = 0; // 0: use system default value
452 int numa_node = port::kNUMANoAffinity;
453 };
454
455 /// A utility routine: copy contents of `src` in file system `src_fs`
456 /// to `target` in file system `target_fs`.
457 Status FileSystemCopyFile(FileSystem* src_fs, const string& src,
458 FileSystem* target_fs, const string& target);
459
460 /// A utility routine: reads contents of named file into `*data`
461 Status ReadFileToString(Env* env, const string& fname, string* data);
462
463 /// A utility routine: write contents of `data` to file named `fname`
464 /// (overwriting existing contents, if any).
465 Status WriteStringToFile(Env* env, const string& fname,
466 const StringPiece& data);
467
468 /// Write binary representation of "proto" to the named file.
469 Status WriteBinaryProto(Env* env, const string& fname,
470 const ::tensorflow::protobuf::MessageLite& proto);
471
472 /// Reads contents of named file and parse as binary encoded proto data
473 /// and store into `*proto`.
474 Status ReadBinaryProto(Env* env, const string& fname,
475 ::tensorflow::protobuf::MessageLite* proto);
476
477 /// Write the text representation of "proto" to the named file.
478 Status WriteTextProto(Env* env, const string& fname,
479 const ::tensorflow::protobuf::Message& proto);
480
481 /// Read contents of named file and parse as text encoded proto data
482 /// and store into `*proto`.
483 template <typename T, typename std::enable_if<!std::is_base_of<
484 protobuf::Message, T>::value>::type* = nullptr>
ReadTextProto(Env * env,const string & fname,T * proto)485 Status ReadTextProto(Env* env, const string& fname, T* proto) {
486 return errors::Unimplemented("Can't parse text protos with protolite.");
487 }
488
489 Status ReadTextProto(Env* env, const string& fname,
490 ::tensorflow::protobuf::Message* proto);
491
492 /// Read contents of named file and parse as either text or binary encoded proto
493 /// data and store into `*proto`.
494 Status ReadTextOrBinaryProto(Env* env, const string& fname,
495 #if !defined(TENSORFLOW_LITE_PROTOS)
496 ::tensorflow::protobuf::Message* proto
497 #else
498 ::tensorflow::protobuf::MessageLite* proto
499 #endif
500 );
501
502 // START_SKIP_DOXYGEN
503
504 // The following approach to register filesystems is deprecated and will be
505 // replaced with modular filesystem plugins registration.
506 // TODO(mihaimaruseac): After all filesystems are converted, remove this.
507 namespace register_file_system {
508
509 template <typename Factory>
510 struct Register {
RegisterRegister511 Register(Env* env, const string& scheme) {
512 // TODO(b/32704451): Don't just ignore the ::tensorflow::Status object!
513 env->RegisterFileSystem(scheme, []() -> FileSystem* { return new Factory; })
514 .IgnoreError();
515 }
516 };
517
518 } // namespace register_file_system
519
520 // END_SKIP_DOXYGEN
521
522 } // namespace tensorflow
523
524 // Register a FileSystem implementation for a scheme. Files with names that have
525 // "scheme://" prefixes are routed to use this implementation.
526 #define REGISTER_FILE_SYSTEM_ENV(env, scheme, factory) \
527 REGISTER_FILE_SYSTEM_UNIQ_HELPER(__COUNTER__, env, scheme, factory)
528 #define REGISTER_FILE_SYSTEM_UNIQ_HELPER(ctr, env, scheme, factory) \
529 REGISTER_FILE_SYSTEM_UNIQ(ctr, env, scheme, factory)
530 #define REGISTER_FILE_SYSTEM_UNIQ(ctr, env, scheme, factory) \
531 static ::tensorflow::register_file_system::Register<factory> \
532 register_ff##ctr TF_ATTRIBUTE_UNUSED = \
533 ::tensorflow::register_file_system::Register<factory>(env, scheme)
534
535 #define REGISTER_FILE_SYSTEM(scheme, factory) \
536 REGISTER_FILE_SYSTEM_ENV(::tensorflow::Env::Default(), scheme, factory);
537
538 #endif // TENSORFLOW_CORE_PLATFORM_ENV_H_
539