Changeset 12726
- Timestamp:
- Oct 2, 2012, 2:03:14 AM (12 years ago)
- Location:
- ps/trunk
- Files:
-
- 2 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
ps/trunk/build/premake/premake4.lua
r12702 r12726 6 6 newoption { trigger = "icc", description = "Use Intel C++ Compiler (Linux only; should use either \"--cc icc\" or --without-pch too, and then set CXX=icpc before calling make)" } 7 7 newoption { trigger = "outpath", description = "Location for generated project files" } 8 newoption { trigger = "without-fam", description = "Disable use of FAM API on Linux" }9 8 newoption { trigger = "without-audio", description = "Disable use of OpenAL/Ogg/Vorbis APIs" } 10 9 newoption { trigger = "minimal-flags", description = "Only set compiler/linker flags that are really needed. Has no effect on Windows builds" } … … 155 154 if _OPTIONS["gles"] then 156 155 defines { "CONFIG2_GLES=1" } 157 end158 159 if _OPTIONS["without-fam"] then160 defines { "CONFIG2_FAM=0" }161 156 end 162 157 … … 781 776 elseif os.is("linux") or os.is("bsd") then 782 777 783 if not _OPTIONS["without-fam"] then784 links { "fam" }785 end786 787 778 if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then 788 779 links { "rt" } … … 1206 1197 elseif os.is("linux") or os.is("bsd") then 1207 1198 1208 if not _OPTIONS["without-fam"] then1209 links { "fam" }1210 end1211 1212 1199 if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then 1213 1200 links { "rt" } -
ps/trunk/source/lib/config2.h
r12550 r12726 102 102 #endif 103 103 104 // allow use of FAM API on Linux105 #ifndef CONFIG2_FAM106 # define CONFIG2_FAM 0107 #endif108 109 104 // allow use of OpenAL/Ogg/Vorbis APIs 110 105 #ifndef CONFIG2_AUDIO -
ps/trunk/source/lib/sysdep/os/linux/dir_watch_inotify.cpp
r12723 r12726 23 23 #include "precompiled.h" 24 24 25 26 27 28 29 25 30 #include <string> 26 27 #include "lib/config2.h" 28 #include "lib/sysdep/sysdep.h" 29 #include "lib/sysdep/dir_watch.h" 30 #include "ps/CLogger.h" 31 32 #if !CONFIG2_FAM 33 34 // stub implementations 35 36 Status dir_watch_Add(const OsPath& UNUSED(path), PDirWatch& UNUSED(dirWatch)) 37 { 38 return INFO::OK; 39 } 40 41 Status dir_watch_Poll(DirWatchNotifications& UNUSED(notifications)) 42 { 43 return INFO::OK; 44 } 45 46 #else 47 48 #include <fam.h> 49 50 // FAMEvent is large (~4KB), so define a smaller structure to store events 31 #include <sys/inotify.h> 32 33 51 34 struct NotificationEvent 52 35 { 53 36 std::string filename; 54 void *userdata;55 FAMCodes code;37 ; 38 ; 56 39 }; 57 40 58 41 // To avoid deadlocks and slow synchronous reads, it's necessary to use a 59 // separate thread for reading events from FAM.42 // separate thread for reading events from . 60 43 // So we just spawn a thread to push events into this list, then swap it out 61 44 // when someone calls dir_watch_Poll. … … 70 53 // trool; -1 = init failed and all operations will be aborted silently. 71 54 // this is so that each dir_* call doesn't complain if the system's 72 // FAMis broken or unavailable.55 // is broken or unavailable. 73 56 static int initialized = 0; 74 57 75 static FAMConnection fc; 58 // Inotify file descriptor 59 static int inotifyfd; 60 61 // With inotify, using a map seems to be a good alternative to FAM's userdata 62 typedef std::map<int, PDirWatch> DirWatchMap; 63 static DirWatchMap g_paths; 76 64 77 65 struct DirWatch … … 85 73 { 86 74 ENSURE(initialized > 0); 87 88 FAMRequest req; 89 req.reqnum = reqnum; 90 FAMCancelMonitor(&fc, &req); 75 inotify_rm_watch(inotifyfd, reqnum); 91 76 } 92 77 … … 95 80 }; 96 81 97 98 82 // for atexit 99 static void fam_deinit()100 { 101 FAMClose(&fc);83 static void _deinit() 84 { 85 ); 102 86 103 87 pthread_cancel(g_event_loop_thread); 104 88 // NOTE: POSIX threads are (by default) only cancellable inside particular 105 89 // functions (like 'select'), so this should safely terminate while it's 106 // in select/ FAMNextEvent/etc (and won't e.g. cancel while it's holding the90 // in select/etc (and won't e.g. cancel while it's holding the 107 91 // mutex) 108 92 … … 111 95 } 112 96 113 static void fam_event_loop_process_events() 114 { 115 while(FAMPending(&fc) > 0) 116 { 117 FAMEvent e; 118 if(FAMNextEvent(&fc, &e) < 0) 119 { 120 debug_printf(L"FAMNextEvent error"); 121 return; 122 } 123 97 static void inotify_event_loop_process_events() 98 { 99 // Buffer for reading the events. 100 // Need to be careful about overflow here. 101 char buffer[65535]; 102 103 // Event iterator 104 ssize_t buffer_i = 0; 105 106 // Total size of all the events 107 ssize_t r; 108 109 // Size & struct for the current event 110 size_t event_size; 111 struct inotify_event *pevent; 112 113 r = read(inotifyfd, buffer, 65535); 114 if(r <= 0) 115 return; 116 117 while(buffer_i < r) 118 { 124 119 NotificationEvent ne; 125 ne.filename = e.filename; 126 ne.userdata = e.userdata; 127 ne.code = e.code; 128 129 pthread_mutex_lock(&g_mutex); 130 g_notifications.push_back(ne); 131 pthread_mutex_unlock(&g_mutex); 132 } 133 } 134 135 static void* fam_event_loop(void*) 136 { 137 int famfd = FAMCONNECTION_GETFD(&fc); 138 120 pevent = (struct inotify_event *) &buffer[buffer_i]; 121 122 event_size = offsetof(struct inotify_event, name) + pevent->len; 123 ne.wd = pevent->wd; 124 ne.filename = pevent->name; 125 ne.code = pevent->mask; 126 127 pthread_mutex_lock(&g_mutex); 128 g_notifications.push_back(ne); 129 pthread_mutex_unlock(&g_mutex); 130 131 buffer_i += event_size; 132 } 133 } 134 135 static void* inotify_event_loop(void*) 136 { 139 137 while(true) 140 138 { 141 139 fd_set fdrset; 142 140 FD_ZERO(&fdrset); 143 FD_SET( famfd, &fdrset);144 141 FD_SET(fd, &fdrset); 142 errno = 0; 145 143 // Block with select until there's events waiting 146 // (Mustn't just block inside FAMNextEvent since fam will deadlock) 147 while(select(famfd+1, &fdrset, NULL, NULL, NULL) < 0) 144 while(select(inotifyfd+1, &fdrset, NULL, NULL, NULL) < 0) 148 145 { 149 146 if(errno == EINTR) … … 151 148 // interrupted - try again 152 149 FD_ZERO(&fdrset); 153 FD_SET( famfd, &fdrset);150 FD_SET(fd, &fdrset); 154 151 } 155 152 else if(errno == EBADF) 156 153 { 157 // probably just lost the connection to FAM- kill the thread158 debug_printf(L" lost connection to FAM");154 // probably just lost the connection to - kill the thread 155 debug_printf(L"); 159 156 return NULL; 160 157 } … … 162 159 { 163 160 // oops 164 �� debug_printf(L" select error %d", errno);161 debug_printf(L"", errno); 165 162 return NULL; 166 163 } 167 }168 169 if(FD_ISSET( famfd, &fdrset))170 fam_event_loop_process_events();164 165 } 166 if(FD_ISSET(fd, &fdrset)) 167 _event_loop_process_events(); 171 168 } 172 169 } … … 174 171 Status dir_watch_Add(const OsPath& path, PDirWatch& dirWatch) 175 172 { 176 // init already failed; don't try again or complain 173 char resolved[PATH_MAX + 1]; 174 175 // init already failed; don't try again or complain 177 176 if(initialized == -1) 178 177 return ERR::FAIL; // NOWARN … … 180 179 if(!initialized) 181 180 { 182 if(FAMOpen2(&fc, "lib_res")) 183 { 181 errno = 0; 182 if((inotifyfd = inotify_init()) < 0) 183 { 184 // Check for error ? 185 int err = errno; 184 186 initialized = -1; 185 LOGERROR(L"Error initializing FAM; hotloading will be disabled"); 186 return ERR::FAIL; // NOWARN 187 } 188 189 if (pthread_create(&g_event_loop_thread, NULL, &fam_event_loop, NULL)) 187 LOGERROR(L"Error initializing inotify file descriptor; hotloading will be disabled, errno=%d", err); 188 errno = err; 189 return StatusFromErrno(); // NOWARN 190 } 191 192 errno = 0; 193 int ret = pthread_create(&g_event_loop_thread, NULL, &inotify_event_loop, NULL); 194 if (ret != 0) 190 195 { 191 196 initialized = -1; 192 LOGERROR(L"Error creating FAM event loop thread; hotloading will be disabled"); 193 return ERR::FAIL; // NOWARN 197 LOGERROR(L"Error creating inotify event loop thread; hotloading will be disabled, err=%d", ret); 198 errno = ret; 199 return StatusFromErrno(); // NOWARN 194 200 } 195 201 196 202 initialized = 1; 197 atexit( fam_deinit);203 atexit(_deinit); 198 204 } 199 205 200 206 PDirWatch tmpDirWatch(new DirWatch); 201 202 // NOTE: It would be possible to use FAMNoExists iff we're building with Gamin 203 // (not FAM), to avoid a load of boring notifications when we add a directory, 204 // but it would only save tens of milliseconds of CPU time, so it's probably 205 // not worthwhile 206 207 FAMRequest req; 208 if(FAMMonitorDirectory(&fc, OsString(path).c_str(), &req, tmpDirWatch.get()) < 0) 209 { 210 debug_warn(L"res_watch_dir failed!"); 211 WARN_RETURN(ERR::FAIL); // no way of getting error code? 212 } 207 errno = 0; 208 int wd = inotify_add_watch(inotifyfd, realpath(OsString(path).c_str(), resolved), IN_CREATE | IN_DELETE | IN_CLOSE_WRITE); 209 if (wd < 0) 210 WARN_RETURN(StatusFromErrno()); 213 211 214 212 dirWatch.swap(tmpDirWatch); 215 213 dirWatch->path = path; 216 dirWatch->reqnum = req.reqnum; 214 dirWatch->reqnum = wd; 215 g_paths.insert(std::make_pair(wd, dirWatch)); 217 216 218 217 return INFO::OK; 219 218 } 220 221 222 219 223 220 Status dir_watch_Poll(DirWatchNotifications& notifications) … … 237 234 { 238 235 DirWatchNotification::EType type; 236 239 237 switch(polled_notifications[i].code) 240 238 { 241 case FAMChanged:239 case : 242 240 type = DirWatchNotification::Changed; 243 241 break; 244 case FAMCreated:242 case : 245 243 type = DirWatchNotification::Created; 246 244 break; 247 case FAMDeleted:245 case : 248 246 type = DirWatchNotification::Deleted; 249 247 break; … … 251 249 continue; 252 250 } 253 DirWatch* dirWatch = (DirWatch*)polled_notifications[i].userdata; 254 OsPath pathname = dirWatch->path / polled_notifications[i].filename; 255 notifications.push_back(DirWatchNotification(pathname, type)); 251 252 DirWatchMap::iterator it = g_paths.find(polled_notifications[i].wd); 253 if(it != g_paths.end()) 254 { 255 OsPath filename = Path(OsString(it->second->path).append(polled_notifications[i].filename)); 256 notifications.push_back(DirWatchNotification(filename, type)); 257 } 258 else 259 { 260 debug_printf(L"dir_watch_Poll: Notification with invalid watch descriptor wd=%d\n", polled_notifications[i].wd); 261 } 256 262 } 257 263 … … 260 266 } 261 267 262 #endif // CONFIG2_FAM
Note:
See TracChangeset
for help on using the changeset viewer.