• 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 #include <dirent.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <fnmatch.h>
20 #include <stdio.h>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <time.h>
26 #include <unistd.h>
27 
28 #include <thread>
29 #include <vector>
30 
31 #include "tensorflow/core/lib/core/error_codes.pb.h"
32 #include "tensorflow/core/platform/env.h"
33 #include "tensorflow/core/platform/load_library.h"
34 #include "tensorflow/core/platform/logging.h"
35 #include "tensorflow/core/platform/posix/posix_file_system.h"
36 
37 namespace tensorflow {
38 
39 namespace {
40 
41 class StdThread : public Thread {
42  public:
43   // name and thread_options are both ignored.
StdThread(const ThreadOptions & thread_options,const string & name,std::function<void ()> fn)44   StdThread(const ThreadOptions& thread_options, const string& name,
45             std::function<void()> fn)
46       : thread_(fn) {}
~StdThread()47   ~StdThread() override { thread_.join(); }
48 
49  private:
50   std::thread thread_;
51 };
52 
53 class PosixEnv : public Env {
54  public:
PosixEnv()55   PosixEnv() {}
56 
~PosixEnv()57   ~PosixEnv() override { LOG(FATAL) << "Env::Default() must not be destroyed"; }
58 
MatchPath(const string & path,const string & pattern)59   bool MatchPath(const string& path, const string& pattern) override {
60     return fnmatch(pattern.c_str(), path.c_str(), FNM_PATHNAME) == 0;
61   }
62 
SleepForMicroseconds(int64 micros)63   void SleepForMicroseconds(int64 micros) override {
64     while (micros > 0) {
65       timespec sleep_time;
66       sleep_time.tv_sec = 0;
67       sleep_time.tv_nsec = 0;
68 
69       if (micros >= 1e6) {
70         sleep_time.tv_sec =
71             std::min<int64>(micros / 1e6, std::numeric_limits<time_t>::max());
72         micros -= static_cast<int64>(sleep_time.tv_sec) * 1e6;
73       }
74       if (micros < 1e6) {
75         sleep_time.tv_nsec = 1000 * micros;
76         micros = 0;
77       }
78       while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {
79         // Ignore signals and wait for the full interval to elapse.
80       }
81     }
82   }
83 
StartThread(const ThreadOptions & thread_options,const string & name,std::function<void ()> fn)84   Thread* StartThread(const ThreadOptions& thread_options, const string& name,
85                       std::function<void()> fn) override {
86     return new StdThread(thread_options, name, fn);
87   }
88 
GetCurrentThreadId()89   int32 GetCurrentThreadId() override {
90 #ifdef __APPLE__
91     uint64_t tid64;
92     pthread_threadid_np(nullptr, &tid64);
93     return static_cast<int32>(tid64);
94 #elif defined(__FreeBSD__)
95     // Has to be casted to long first, else this error appears:
96     // static_cast from 'pthread_t' (aka 'pthread *') to 'int32' (aka 'int')
97     // is not allowed
98     return static_cast<int32>(static_cast<int64>(pthread_self()));
99 #else
100     return static_cast<int32>(pthread_self());
101 #endif
102   }
103 
GetCurrentThreadName(string * name)104   bool GetCurrentThreadName(string* name) override {
105 #if defined(__ANDROID__) || defined(__EMSCRIPTEN__)
106     return false;
107 #else
108     char buf[100];
109     int res = pthread_getname_np(pthread_self(), buf, static_cast<size_t>(100));
110     if (res != 0) {
111       return false;
112     }
113     *name = buf;
114     return true;
115 #endif
116   }
117 
SchedClosure(std::function<void ()> closure)118   void SchedClosure(std::function<void()> closure) override {
119     // TODO(b/27290852): Spawning a new thread here is wasteful, but
120     // needed to deal with the fact that many `closure` functions are
121     // blocking in the current codebase.
122     std::thread closure_thread(closure);
123     closure_thread.detach();
124   }
125 
SchedClosureAfter(int64 micros,std::function<void ()> closure)126   void SchedClosureAfter(int64 micros, std::function<void()> closure) override {
127     // TODO(b/27290852): Consuming a thread here is wasteful, but this
128     // code is (currently) only used in the case where a step fails
129     // (AbortStep). This could be replaced by a timer thread
130     SchedClosure([this, micros, closure]() {
131       SleepForMicroseconds(micros);
132       closure();
133     });
134   }
135 
LoadLibrary(const char * library_filename,void ** handle)136   Status LoadLibrary(const char* library_filename, void** handle) override {
137     return tensorflow::internal::LoadLibrary(library_filename, handle);
138   }
139 
GetSymbolFromLibrary(void * handle,const char * symbol_name,void ** symbol)140   Status GetSymbolFromLibrary(void* handle, const char* symbol_name,
141                               void** symbol) override {
142     return tensorflow::internal::GetSymbolFromLibrary(handle, symbol_name,
143                                                       symbol);
144   }
145 
FormatLibraryFileName(const string & name,const string & version)146   string FormatLibraryFileName(const string& name,
147                                const string& version) override {
148     return tensorflow::internal::FormatLibraryFileName(name, version);
149   }
150 
GetRunfilesDir()151   string GetRunfilesDir() override {
152     string bin_path = this->GetExecutablePath();
153     string runfiles_suffix = ".runfiles/org_tensorflow";
154     std::size_t pos = bin_path.find(runfiles_suffix);
155 
156     // Sometimes (when executing under python) bin_path returns the full path to
157     // the python scripts under runfiles. Get the substring.
158     if (pos != std::string::npos) {
159       return bin_path.substr(0, pos + runfiles_suffix.length());
160     }
161 
162     // See if we have the executable path. if executable.runfiles exists, return
163     // that folder.
164     string runfiles_path = bin_path + runfiles_suffix;
165     Status s = this->IsDirectory(runfiles_path);
166     if (s.ok()) {
167       return runfiles_path;
168     }
169 
170     // If nothing can be found, return something close.
171     return bin_path.substr(0, bin_path.find_last_of("/\\"));
172   }
173 
174  private:
175   void GetLocalTempDirectories(std::vector<string>* list) override;
176 };
177 
178 }  // namespace
179 
180 #if defined(PLATFORM_POSIX) || defined(__ANDROID__)
181 REGISTER_FILE_SYSTEM("", PosixFileSystem);
182 REGISTER_FILE_SYSTEM("file", LocalPosixFileSystem);
Default()183 Env* Env::Default() {
184   static Env* default_env = new PosixEnv;
185   return default_env;
186 }
187 #endif
188 
GetLocalTempDirectories(std::vector<string> * list)189 void PosixEnv::GetLocalTempDirectories(std::vector<string>* list) {
190   list->clear();
191   // Directories, in order of preference. If we find a dir that
192   // exists, we stop adding other less-preferred dirs
193   const char* candidates[] = {
194     // Non-null only during unittest/regtest
195     getenv("TEST_TMPDIR"),
196 
197     // Explicitly-supplied temp dirs
198     getenv("TMPDIR"),
199     getenv("TMP"),
200 
201 #if defined(__ANDROID__)
202     "/data/local/tmp",
203 #endif
204 
205     // If all else fails
206     "/tmp",
207   };
208 
209   for (const char* d : candidates) {
210     if (!d || d[0] == '\0') continue;  // Empty env var
211 
212     // Make sure we don't surprise anyone who's expecting a '/'
213     string dstr = d;
214     if (dstr[dstr.size() - 1] != '/') {
215       dstr += "/";
216     }
217 
218     struct stat statbuf;
219     if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode) &&
220         !access(dstr.c_str(), 0)) {
221       // We found a dir that exists and is accessible - we're done.
222       list->push_back(dstr);
223       return;
224     }
225   }
226 }
227 
228 }  // namespace tensorflow
229