• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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