Changeset 28882 in vbox for trunk/src/VBox/Main/linux
- Timestamp:
- Apr 28, 2010 11:17:52 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/linux/HostHardwareLinux.cpp
r28847 r28882 7 7 8 8 /* 9 * Copyright (C) 2008 Oracle Corporation9 * Copyright (C) 2008-2010 Oracle Corporation 10 10 * 11 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 17 17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 18 * 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa 20 * Clara, CA 95054 USA or visit http://www.sun.com if you need 21 * additional information or have any questions. 18 22 */ 19 23 … … 40 44 #include <iprt/param.h> 41 45 #include <iprt/path.h> 42 #include <iprt/pipe.h>43 #include <iprt/poll.h>44 #include <iprt/socket.h>45 46 #include <iprt/string.h> 46 47 #include <iprt/thread.h> /* for RTThreadSleep() */ … … 54 55 55 56 #ifdef VBOX_USB_WITH_SYSFS 56 # ifdef VBOX_USB_WITH_FAM 57 # include <fam.h> 57 # ifdef VBOX_USB_WITH_INOTIFY 58 # include <dlfcn.h> 59 # include <fcntl.h> 60 # include <poll.h> 61 # include <signal.h> 62 # include <unistd.h> 58 63 # endif 59 64 #endif … … 93 98 bool *pfSuccess); 94 99 #ifdef VBOX_USB_WITH_SYSFS 95 # ifdef VBOX_USB_WITH_ FAM100 # ifdef VBOX_USB_WITH_INOTIFY 96 101 static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, bool *pfSuccess); 102 103 /** Function object to be invoked on filenames from a directory. */ 104 class pathHandler 105 { 106 /** Called on each element of the sysfs directory. Can e.g. store 107 * interesting entries in a list. */ 108 virtual bool handle(const char *pcszNode) = 0; 109 public: 110 bool doHandle(const char *pcszNode) 111 { 112 AssertPtr(pcszNode); 113 Assert(pcszNode[0] == '/'); 114 return handle(pcszNode); 115 } 116 }; 117 118 static int walkDirectory(const char *pcszPath, pathHandler *pHandler, 119 bool useRealPath); 120 static int getDeviceInfoFromSysfs(const char *pcszPath, pathHandler *pHandler); 97 121 # endif 98 122 # ifdef VBOX_USB_WITH_DBUS … … 1040 1064 success = halSuccess; 1041 1065 # endif /* VBOX_USB_WITH_DBUS */ 1042 # ifdef VBOX_USB_WITH_ FAM1066 # ifdef VBOX_USB_WITH_INOTIFY 1043 1067 if ( RT_SUCCESS(rc) 1044 1068 && (!success || testing())) … … 1067 1091 /** A flag to say that we wish to interrupt the current wait. */ 1068 1092 volatile bool mInterrupt; 1093 /** The constructor "return code" */ 1094 int mStatus; 1069 1095 1070 1096 public: 1071 1097 /** Test whether this implementation can be used on the current system */ 1072 static bool HalAvailable(void)1098 static bool Available(void) 1073 1099 { 1074 1100 RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection; … … 1087 1113 /** @copydoc VBoxMainHotplugWaiter::Interrupt */ 1088 1114 virtual void Interrupt (void); 1115 /** @copydoc VBoxMainHotplugWaiter::getStatus */ 1116 virtual int getStatus(void) 1117 { 1118 return mStatus; 1119 } 1089 1120 }; 1090 1121 … … 1095 1126 hotplugDBusImpl::hotplugDBusImpl (void) : mTriggered(false), mInterrupt(false) 1096 1127 { 1097 int rc = VINF_SUCCESS;1098 1099 if (RT_SUCCESS( RTDBusLoadLib()))1128 int rc; 1129 1130 if (RT_SUCCESS(rc = RTDBusLoadLib())) 1100 1131 { 1101 1132 for (unsigned i = 0; RT_SUCCESS(rc) && i < 5 && !mConnection; ++i) … … 1117 1148 mConnection.reset(); 1118 1149 } 1150 mStatus = rc; 1119 1151 } 1120 1152 … … 1178 1210 /** @copydoc VBoxMainHotplugWaiter::Interrupt */ 1179 1211 virtual void Interrupt (void) {} 1212 virtual int getStatus(void) 1213 { 1214 return VERR_NOT_SUPPORTED; 1215 } 1216 1180 1217 }; 1181 1218 1182 1219 #ifdef VBOX_USB_WITH_SYSFS 1183 # ifdef VBOX_USB_WITH_FAM 1220 # ifdef VBOX_USB_WITH_INOTIFY 1221 /** Class wrapper around an inotify watch (or a group of them to be precise). 1222 * Inherits from pathHandler so that it can be passed to walkDirectory() to 1223 * easily add all files from a directory. */ 1224 class inotifyWatch : public pathHandler 1225 { 1226 /** Pointer to the inotify_add_watch() glibc function/Linux API */ 1227 int (*inotify_add_watch)(int, const char *, uint32_t); 1228 /** The native handle of the inotify fd. */ 1229 int mhInotify; 1230 /** Object initialisation status, to save us throwing an exception from 1231 * the constructor if we can't initialise */ 1232 int mStatus; 1233 1234 /** Object initialistation */ 1235 int initInotify(void); 1236 1237 public: 1238 /** Add @a pcszPath to the list of files and directories to be monitored */ 1239 virtual bool handle(const char *pcszPath); 1240 1241 inotifyWatch(void) : mhInotify(-1) 1242 { 1243 mStatus = initInotify(); 1244 } 1245 1246 ~inotifyWatch(void) 1247 { 1248 close(mhInotify); 1249 } 1250 1251 int getStatus(void) 1252 { 1253 return mStatus; 1254 } 1255 1256 int getFD(void) 1257 { 1258 AssertRCReturn(mStatus, -1); 1259 return mhInotify; 1260 } 1261 }; 1262 1263 int inotifyWatch::initInotify(void) 1264 { 1265 int (*inotify_init)(void); 1266 int fd, flags; 1267 1268 errno = 0; 1269 *(void **)(&inotify_init) = dlsym(RTLD_DEFAULT, "inotify_init"); 1270 if (!inotify_init) 1271 return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND; 1272 *(void **)(&inotify_add_watch) = dlsym(RTLD_DEFAULT, "inotify_add_watch"); 1273 if (!inotify_add_watch) 1274 return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND; 1275 fd = inotify_init(); 1276 if (fd < 0) 1277 { 1278 Assert(errno > 0); 1279 return RTErrConvertFromErrno(errno); 1280 } 1281 Assert(errno == 0); 1282 1283 int rc = VINF_SUCCESS; 1284 1285 flags = fcntl(fd, F_GETFL, NULL); 1286 if ( flags < 0 1287 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) 1288 { 1289 Assert(errno > 0); 1290 rc = RTErrConvertFromErrno(errno); 1291 } 1292 if (RT_FAILURE(rc)) 1293 close(fd); 1294 else 1295 { 1296 Assert(errno == 0); 1297 mhInotify = fd; 1298 } 1299 return rc; 1300 } 1301 1302 /** The flags we pass to inotify - modify, create, delete */ 1303 #define IN_FLAGS 0x302 1304 1305 bool inotifyWatch::handle(const char *pcszPath) 1306 { 1307 AssertRCReturn(mStatus, false); 1308 errno = 0; 1309 if ( inotify_add_watch(mhInotify, pcszPath, IN_FLAGS) >= 0 1310 || (errno == EACCES)) 1311 return true; 1312 /* Other errors listed in the manpage can be treated as fatal */ 1313 return false; 1314 } 1184 1315 1185 1316 # define SYSFS_USB_DEVICE_PATH "/dev/bus/usb" 1186 1317 # define SYSFS_WAKEUP_STRING "Wake up!" 1187 1318 1188 class hotplug SysfsFAMImpl : public VBoxMainHotplugWaiterImpl1319 class hotplugInotifyImpl : public VBoxMainHotplugWaiterImpl 1189 1320 { 1190 1321 /** Pipe used to interrupt wait(), the read end. */ 1191 RTPIPEmhWakeupPipeR;1322 int mhWakeupPipeR; 1192 1323 /** Pipe used to interrupt wait(), the write end. */ 1193 RTPIPE mhWakeupPipeW; 1194 /** Our connection to FAM for polling for changes on sysfs. */ 1195 FAMConnection mFAMConnection; 1196 /** Has our connection been initialised? */ 1197 bool mfFAMInitialised; 1198 /** The iprt native handle of the FAM fd socket. */ 1199 RTSOCKET mhFAMFD; 1200 /** Poll set containing the FAM socket and the termination pipe */ 1201 RTPOLLSET mhPollSet; 1324 int mhWakeupPipeW; 1325 /** The inotify watch set */ 1326 inotifyWatch mWatches; 1202 1327 /** Flag to mark that the Wait() method is currently being called, and to 1203 1328 * ensure that it isn't called multiple times in parallel. */ 1204 uint32_t mfWaiting;1329 volatile uint32_t mfWaiting; 1205 1330 /** iprt result code from object initialisation. Should be AssertReturn-ed 1206 1331 * on at the start of all methods. I went this way because I didn't want … … 1211 1336 enum 1212 1337 { 1213 RPIPE_ID = 1, 1214 FAMFD_ID 1338 RPIPE_ID = 0, 1339 INOTIFY_ID, 1340 MAX_POLLID 1215 1341 }; 1216 1217 /** Initialise the connection to the FAM daemon, allocating all required1218 * resources.1219 * @returns iprt status code1220 */1221 int initConnection(void);1222 1223 /** Clean up the connection to the FAM daemon, freeing any allocated1224 * resources and gracefully skipping over any which have not yet been1225 * allocated or already cleaned up.1226 * @returns iprt status code1227 */1228 void termConnection(void);1229 1342 1230 1343 /** Clean up any resources in use, gracefully skipping over any which have … … 1233 1346 void term(void); 1234 1347 1235 /** Make sure that the object is correctly initialised and re-initialises 1236 * it if not, and if the maximum number of connection attempts has not been 1237 * reached. 1238 * @returns iprt status value 1239 * @returns VERR_TRY_AGAIN if we are giving up on this attempt but may 1240 * still succeed on future attempts 1241 */ 1242 int checkConnection(void); 1243 1244 /** Quick failure test of the checkConnection() function. */ 1245 void testCheckConnection(void); 1246 1247 /** Open our connection to FAM and convert the status to iprt. 1248 * @todo really convert the status 1249 */ 1250 int openFAM(void) 1251 { 1252 if (FAMOpen(&mFAMConnection) < 0) 1253 return VERR_FAM_OPEN_FAILED; 1254 mfFAMInitialised = true; 1255 return VINF_SUCCESS; 1256 } 1257 1258 /** Monitor a file through the FAM connection. */ 1259 int monitorDirectoryFAM(const char *pszName) 1260 { 1261 AssertReturn(mfFAMInitialised, VERR_WRONG_ORDER); 1262 FAMRequest dummyReq; 1263 if (FAMMonitorDirectory(&mFAMConnection, pszName, &dummyReq, NULL) < 0) 1264 return VERR_FAM_MONITOR_DIRECTORY_FAILED; 1265 return VINF_SUCCESS; 1266 } 1267 1268 /** Quick failure test of the monitor function - we temporarily invalidate 1269 * the connection FD to trigger an error path. */ 1270 void testMonitorDirectoryFAM(void) 1271 { 1272 int oldFD = FAMCONNECTION_GETFD(&mFAMConnection); 1273 FAMCONNECTION_GETFD(&mFAMConnection) = -1; 1274 Assert(monitorDirectoryFAM("") == VERR_FAM_MONITOR_DIRECTORY_FAILED); 1275 FAMCONNECTION_GETFD(&mFAMConnection) = oldFD; 1276 } 1277 1278 int nextEventFAM(FAMEvent *pEv) 1279 { 1280 if (FAMNextEvent(&mFAMConnection, pEv) == 1) 1281 return VINF_SUCCESS; 1282 mStatus = VERR_FAM_CONNECTION_LOST; 1283 return VERR_TRY_AGAIN; 1284 } 1285 1286 /** Quick failure test of the nextevent function. */ 1287 void testNextEventFAM(void) 1288 { 1289 int oldStatus = mStatus; 1290 mStatus = VINF_SUCCESS; 1291 //Assert(nextEventFAM(NULL) == VERR_TRY_AGAIN); 1292 mStatus = oldStatus; 1293 } 1294 1295 /** Close our connection to FAM. We ignore errors as there is no 1296 * documentation as to what they mean, and the only error which might 1297 * interest us (EINTR) should be (but isn't) handled inside the library. */ 1298 void closeFAM(void) 1299 { 1300 if (mfFAMInitialised) 1301 FAMClose(&mFAMConnection); 1302 mfFAMInitialised = false; 1303 } 1348 int drainInotify(); 1304 1349 1305 1350 /** Read the wakeup string from the wakeup pipe */ 1306 1351 int drainWakeupPipe(void); 1307 1352 public: 1308 hotplug SysfsFAMImpl(void);1309 virtual ~hotplug SysfsFAMImpl(void)1353 hotplugInotifyImpl(void); 1354 virtual ~hotplugInotifyImpl(void) 1310 1355 { 1311 1356 term(); … … 1316 1361 #endif 1317 1362 } 1318 /** Is sysfs available on this system? If so we expect that this 1319 * implementation will be usable. */ 1320 static bool SysfsAvailable(void) 1321 { 1322 return RTDirExists(SYSFS_USB_DEVICE_PATH); 1323 } 1363 /** Are sysfs and inotify available on this system? If so we expect that 1364 * this implementation will be usable. */ 1365 static bool Available(void) 1366 { 1367 return ( RTDirExists(SYSFS_USB_DEVICE_PATH) 1368 && dlsym(RTLD_DEFAULT, "inotify_init") != NULL); 1369 } 1370 1371 virtual int getStatus(void) 1372 { 1373 return mStatus; 1374 } 1375 1324 1376 /** @copydoc VBoxMainHotplugWaiter::Wait */ 1325 1377 virtual int Wait(RTMSINTERVAL); … … 1328 1380 }; 1329 1381 1330 hotplugSysfsFAMImpl::hotplugSysfsFAMImpl(void) : 1331 mhWakeupPipeR(NIL_RTPIPE), mhWakeupPipeW(NIL_RTPIPE), 1332 mfFAMInitialised(false), mhFAMFD(NIL_RTSOCKET), mhPollSet(NIL_RTPOLLSET), 1333 mfWaiting(0), mStatus(VERR_WRONG_ORDER) 1382 /** Simplified version of RTPipeCreate */ 1383 static int pipeCreateSimple(int *phPipeRead, int *phPipeWrite) 1384 { 1385 AssertPtrReturn(phPipeRead, VERR_INVALID_POINTER); 1386 AssertPtrReturn(phPipeWrite, VERR_INVALID_POINTER); 1387 1388 /* 1389 * Create the pipe and set the close-on-exec flag if requested. 1390 */ 1391 int aFds[2] = {-1, -1}; 1392 if (pipe(aFds)) 1393 return RTErrConvertFromErrno(errno); 1394 1395 *phPipeRead = aFds[0]; 1396 *phPipeWrite = aFds[1]; 1397 1398 /* 1399 * Before we leave, make sure to shut up SIGPIPE. 1400 */ 1401 signal(SIGPIPE, SIG_IGN); 1402 return VINF_SUCCESS; 1403 } 1404 1405 hotplugInotifyImpl::hotplugInotifyImpl(void) : 1406 mhWakeupPipeR(-1), mhWakeupPipeW(-1), mfWaiting(0), 1407 mStatus(VERR_WRONG_ORDER) 1334 1408 { 1335 1409 # ifdef DEBUG … … 1342 1416 if (!testing()) 1343 1417 { 1344 # ifndef VBOX_WITH_SYSFS_BY_DEFAULT1345 /** @todo only create this object if we will use it */1346 // Assert(!RTFileExists("/proc/bus/usb/devices"));1347 # endif1348 1418 # ifdef VBOX_USB_WITH_DBUS 1349 Assert(!hotplugDBusImpl:: HalAvailable());1419 Assert(!hotplugDBusImpl::Available()); 1350 1420 # endif 1351 1421 } … … 1353 1423 int rc; 1354 1424 do { 1355 if (RT_FAILURE(rc = RTPipeCreate(&mhWakeupPipeR, &mhWakeupPipeW, 0)))1425 if (RT_FAILURE(rc = mWatches.getStatus())) 1356 1426 break; 1357 if (RT_FAILURE(rc = initConnection())) 1427 mWatches.doHandle(SYSFS_USB_DEVICE_PATH); 1428 if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW))) 1358 1429 break; 1359 # ifdef DEBUG1360 /** Other tests */1361 testMonitorDirectoryFAM();1362 testNextEventFAM();1363 testCheckConnection();1364 # endif1365 1430 } while(0); 1366 1431 mStatus = rc; … … 1369 1434 } 1370 1435 1371 int hotplugSysfsFAMImpl::initConnection(void) 1372 { 1373 int rc; 1374 1375 if (RT_FAILURE(rc = openFAM())) 1376 return rc; 1377 if (RT_FAILURE(rc = RTSocketFromNative 1378 (&mhFAMFD, FAMCONNECTION_GETFD(&mFAMConnection)))) 1379 return rc; 1380 if (RT_FAILURE(rc = monitorDirectoryFAM(SYSFS_USB_DEVICE_PATH))) 1381 return rc; 1382 if (RT_FAILURE(rc = RTPollSetCreate(&mhPollSet))) 1383 return rc; 1384 if (RT_FAILURE(rc = RTPollSetAddSocket 1385 (mhPollSet, mhFAMFD, RTPOLL_EVT_READ, FAMFD_ID))) 1386 return rc; 1387 AssertReturn(mhWakeupPipeR != NIL_RTPIPE, VERR_WRONG_ORDER); 1388 if (RT_FAILURE(rc = RTPollSetAddPipe(mhPollSet, mhWakeupPipeR, 1389 RTPOLL_EVT_READ, RPIPE_ID))) 1390 return rc; 1391 return VINF_SUCCESS; 1392 } 1393 1394 void hotplugSysfsFAMImpl::termConnection(void) 1395 { 1396 closeFAM(); 1397 mhFAMFD = NIL_RTSOCKET; 1398 RTPollSetDestroy(mhPollSet); 1399 mhPollSet = NIL_RTPOLLSET; 1400 } 1401 1402 int hotplugSysfsFAMImpl::checkConnection(void) 1403 { 1404 /** We should only be called from within Wait(). */ 1405 AssertReturn(mfWaiting, VERR_WRONG_ORDER); 1406 if (mStatus == VERR_FAM_CONNECTION_LOST) 1407 { 1408 termConnection(); 1409 mStatus = initConnection(); 1410 } 1411 return mStatus; 1412 } 1413 1414 void hotplugSysfsFAMImpl::testCheckConnection(void) 1415 { 1416 int oldStatus = mStatus; 1417 mStatus = VERR_UNRESOLVED_ERROR; 1418 1419 bool fEntered = ASMAtomicCmpXchgU32(&mfWaiting, 1, 0); 1420 AssertReturnVoid(fEntered); 1421 Assert(checkConnection() == VERR_UNRESOLVED_ERROR); 1422 mStatus = VERR_FAM_CONNECTION_LOST; 1423 AssertRC(checkConnection()); 1424 mStatus = oldStatus; 1425 mfWaiting = 0; 1426 } 1427 1428 void hotplugSysfsFAMImpl::term(void) 1436 void hotplugInotifyImpl::term(void) 1429 1437 { 1430 1438 /** This would probably be a pending segfault, so die cleanly */ 1431 1439 AssertRelease(!mfWaiting); 1432 termConnection(); 1433 RTPipeClose(mhWakeupPipeR); 1434 mhWakeupPipeR = NIL_RTPIPE; 1435 RTPipeClose(mhWakeupPipeW); 1436 mhWakeupPipeW = NIL_RTPIPE; 1437 } 1438 1439 /** Does a FAM event code mean that the available devices have (probably) 1440 * changed? */ 1441 static int sysfsGetStatusForFAMCode(FAMCodes enmCode) 1442 { 1443 if (enmCode == FAMExists || enmCode == FAMEndExist) 1444 return VERR_TRY_AGAIN; 1440 close(mhWakeupPipeR); 1441 mhWakeupPipeR = -1; 1442 close(mhWakeupPipeW); 1443 mhWakeupPipeW = -1; 1444 } 1445 1446 int hotplugInotifyImpl::drainInotify() 1447 { 1448 char chBuf[RTPATH_MAX + 256]; /* Should always be big enough */ 1449 ssize_t cchRead; 1450 1451 AssertRCReturn(mStatus, VERR_WRONG_ORDER); 1452 errno = 0; 1453 do { 1454 cchRead = read(mWatches.getFD(), chBuf, sizeof(chBuf)); 1455 } while (cchRead > 0); 1456 if (cchRead == 0) 1457 return VINF_SUCCESS; 1458 if (cchRead < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) 1459 return VINF_SUCCESS; 1460 Assert(errno > 0); 1461 return RTErrConvertFromErrno(errno); 1462 } 1463 1464 int hotplugInotifyImpl::drainWakeupPipe(void) 1465 { 1466 char szBuf[sizeof(SYSFS_WAKEUP_STRING)]; 1467 ssize_t cbRead; 1468 1469 AssertRCReturn(mStatus, VERR_WRONG_ORDER); 1470 cbRead = read(mhWakeupPipeR, szBuf, sizeof(szBuf)); 1471 Assert(cbRead > 0); 1445 1472 return VINF_SUCCESS; 1446 1473 } 1447 1474 1448 int hotplugSysfsFAMImpl::drainWakeupPipe(void) 1449 { 1450 char szBuf[sizeof(SYSFS_WAKEUP_STRING)]; 1451 size_t cbDummy; 1452 1453 int rc = RTPipeRead(mhWakeupPipeR, szBuf, sizeof(szBuf), &cbDummy); 1454 AssertRC(rc); 1455 return VINF_SUCCESS; 1456 } 1457 1458 int hotplugSysfsFAMImpl::Wait(RTMSINTERVAL aMillies) 1459 { 1460 uint32_t id; 1475 int hotplugInotifyImpl::Wait(RTMSINTERVAL aMillies) 1476 { 1461 1477 int rc; 1462 FAMEvent ev; 1463 1478 1479 AssertRCReturn(mStatus, VERR_WRONG_ORDER); 1464 1480 bool fEntered = ASMAtomicCmpXchgU32(&mfWaiting, 1, 0); 1465 1481 AssertReturn(fEntered, VERR_WRONG_ORDER); 1466 1482 do { 1467 if (RT_FAILURE(rc = checkConnection())) 1483 struct pollfd pollFD[MAX_POLLID]; 1484 1485 if (RT_FAILURE(rc = walkDirectory(SYSFS_USB_DEVICE_PATH, &mWatches, 1486 false))) 1468 1487 break; 1469 /* timeout returns */ 1470 if (RT_FAILURE(rc = RTPoll(mhPollSet, aMillies, NULL, &id))) 1488 pollFD[RPIPE_ID].fd = mhWakeupPipeR; 1489 pollFD[RPIPE_ID].events = POLLIN; 1490 pollFD[INOTIFY_ID].fd = mWatches.getFD(); 1491 pollFD[INOTIFY_ID].events = POLLIN | POLLERR | POLLHUP; 1492 errno = 0; 1493 int cPolled = poll(pollFD, RT_ELEMENTS(pollFD), aMillies); 1494 if (cPolled < 0) 1495 { 1496 Assert(errno > 0); 1497 rc = RTErrConvertFromErrno(errno); 1498 } 1499 else if (pollFD[RPIPE_ID].revents) 1500 { 1501 rc = drainWakeupPipe(); 1502 if (RT_SUCCESS(rc)) 1503 rc = VERR_INTERRUPTED; 1471 1504 break; 1472 if (id == RPIPE_ID) 1473 { 1474 rc = drainWakeupPipe(); 1505 } 1506 else if (!(pollFD[INOTIFY_ID].revents)) 1507 { 1508 AssertBreakStmt(cPolled == 0, rc = VERR_INTERNAL_ERROR); 1509 rc = VERR_TIMEOUT; 1510 } 1511 Assert(errno == 0 || (RT_FAILURE(rc) && rc != VERR_TIMEOUT)); 1512 if (RT_FAILURE(rc)) 1475 1513 break; 1476 } 1477 AssertBreakStmt(id == FAMFD_ID, rc = VERR_NOT_SUPPORTED); 1478 if (RT_FAILURE(rc = nextEventFAM(&ev))) 1514 AssertBreakStmt(cPolled == 1, rc = VERR_INTERNAL_ERROR); 1515 if (RT_FAILURE(rc = drainInotify())) 1479 1516 break; 1480 rc = sysfsGetStatusForFAMCode(ev.code);1481 1517 } while (false); 1482 1518 mfWaiting = 0; 1483 /* If at all, this should only get called once. */1484 AssertLogRelMsg( RT_SUCCESS(rc)1485 || rc == VERR_TRY_AGAIN1486 || rc == VERR_FAM_OPEN_FAILED1487 || rc == VERR_TIMEOUT, ("rc = %Rrc\n", rc));1488 1519 return rc; 1489 1520 } 1490 1521 1491 void hotplug SysfsFAMImpl::Interrupt(void)1492 { 1493 size_t cbDummy;1494 int rc = RTPipeWrite(mhWakeupPipeW, SYSFS_WAKEUP_STRING,1495 sizeof(SYSFS_WAKEUP_STRING) , &cbDummy);1496 if ( RT_SUCCESS(rc))1497 RTPipeFlush(mhWakeupPipeW);1498 } 1499 1500 # endif /* VBOX_USB_WITH_ FAM*/1522 void hotplugInotifyImpl::Interrupt(void) 1523 { 1524 AssertRCReturnVoid(mStatus); 1525 ssize_t cbWritten = write(mhWakeupPipeW, SYSFS_WAKEUP_STRING, 1526 sizeof(SYSFS_WAKEUP_STRING)); 1527 if (cbWritten > 0) 1528 fsync(mhWakeupPipeW); 1529 } 1530 1531 # endif /* VBOX_USB_WITH_INOTIFY */ 1501 1532 #endif /* VBOX_USB_WTH_SYSFS */ 1502 1533 1503 1534 VBoxMainHotplugWaiter::VBoxMainHotplugWaiter(void) 1504 1535 { 1536 try 1537 { 1505 1538 #ifdef VBOX_USB_WITH_SYSFS 1506 # ifdef VBOX_ USB_WITH_DBUS1507 if (hotplugDBusImpl::HalAvailable())1508 {1509 mImpl = new hotplugDBusImpl;1510 return;1511 }1512 # endif /* VBOX_ USB_WITH_DBUS */1513 # ifdef VBOX_USB_WITH_ FAM1514 if (hotplugSysfsFAMImpl::SysfsAvailable())1515 {1516 mImpl = new hotplugSysfsFAMImpl;1517 return;1518 }1519 # endif /* VBOX_USB_WITH_ FAM*/1539 # ifdef VBOX_WITH_DBUS 1540 if (hotplugDBusImpl::Available()) 1541 { 1542 mImpl = new hotplugDBusImpl; 1543 return; 1544 } 1545 # endif /* VBOX_WITH_DBUS */ 1546 # ifdef VBOX_USB_WITH_INOTIFY 1547 if (hotplugInotifyImpl::Available()) 1548 { 1549 mImpl = new hotplugInotifyImpl; 1550 return; 1551 } 1552 # endif /* VBOX_USB_WITH_INOTIFY */ 1520 1553 #endif /* VBOX_USB_WITH_SYSFS */ 1521 mImpl = new hotplugNullImpl; 1554 mImpl = new hotplugNullImpl; 1555 } 1556 catch(std::bad_alloc &e) 1557 { } 1522 1558 } 1523 1559 1524 1560 #ifdef VBOX_USB_WITH_SYSFS 1525 # ifdef VBOX_USB_WITH_FAM 1526 class sysfsPathHandler 1527 { 1528 /** Called on each element of the sysfs directory. Can e.g. store 1529 * interesting entries in a list. */ 1530 virtual bool handle(const char *pcszNode) = 0; 1531 public: 1532 bool doHandle(const char *pcszNode) 1533 { 1534 AssertPtr(pcszNode); 1535 Assert(pcszNode[0] == '/'); 1536 Assert(RTPathExists(pcszNode)); 1537 return handle(pcszNode); 1538 } 1539 }; 1540 1541 /** 1542 * Helper function to walk a sysfs directory for extracting information about 1543 * devices. 1561 # ifdef VBOX_USB_WITH_INOTIFY 1562 /** 1563 * Helper function to walk a directory, calling a function object on its files 1544 1564 * @returns iprt status code 1545 * @param pcszPath Sysfs directory to walk. Must exist. 1546 * @param pHandler Handler object which will be invoked on each directory 1547 * entry 1565 * @param pcszPath Directory to walk. 1566 * @param pHandler Handler object which will be invoked on each file 1567 * @param useRealPath Whether to resolve the filename to its real path 1568 * before calling the handler. In this case the target 1569 * must exist. 1548 1570 * 1549 1571 * @returns IPRT status code 1550 1572 */ 1551 1573 /* static */ 1552 int getDeviceInfoFromSysfs(const char *pcszPath, sysfsPathHandler *pHandler)1574 int walkDirectory(const char *pcszPath, pathHandler *pHandler, bool useRealPath) 1553 1575 { 1554 1576 AssertPtrReturn(pcszPath, VERR_INVALID_POINTER); … … 1559 1581 1560 1582 rc = RTDirOpen(&pDir, pcszPath); 1561 AssertRCReturn(rc, rc); 1583 if (RT_FAILURE(rc)) 1584 return rc; 1562 1585 while (RT_SUCCESS(rc)) 1563 1586 { … … 1577 1600 if (RT_FAILURE(rc)) 1578 1601 break; 1579 rc = RTPathReal(szPath, szAbsPath, sizeof(szAbsPath)); 1580 AssertRCBreak(rc); /* sysfs should guarantee that this exists */ 1581 if (!pHandler->doHandle(szAbsPath)) 1582 break; 1602 if (useRealPath) 1603 { 1604 rc = RTPathReal(szPath, szAbsPath, sizeof(szAbsPath)); 1605 AssertRCBreak(rc); /* sysfs should guarantee that this exists */ 1606 if (!pHandler->doHandle(szAbsPath)) 1607 break; 1608 } 1609 else 1610 if (!pHandler->doHandle(szPath)) 1611 break; 1583 1612 } 1584 1613 RTDirClose(pDir); … … 1590 1619 1591 1620 1621 /** 1622 * Helper function to walk a sysfs directory for extracting information about 1623 * devices. 1624 * @returns iprt status code 1625 * @param pcszPath Sysfs directory to walk. Must exist. 1626 * @param pHandler Handler object which will be invoked on each directory 1627 * entry 1628 * 1629 * @returns IPRT status code 1630 */ 1631 /* static */ 1632 int getDeviceInfoFromSysfs(const char *pcszPath, pathHandler *pHandler) 1633 { 1634 return walkDirectory(pcszPath, pHandler, true); 1635 } 1636 1637 1592 1638 #define USBDEVICE_MAJOR 189 1593 1639 … … 1616 1662 * interface. To be used with getDeviceInfoFromSysfs(). 1617 1663 */ 1618 class matchUSBDevice : public sysfsPathHandler1664 class matchUSBDevice : public pathHandler 1619 1665 { 1620 1666 USBDeviceInfoList *mList; … … 1657 1703 * device. To be used with getDeviceInfoFromSysfs(). 1658 1704 */ 1659 class matchUSBInterface : public sysfsPathHandler1705 class matchUSBInterface : public pathHandler 1660 1706 { 1661 1707 USBDeviceInfo *mInfo; … … 1759 1805 return rc; 1760 1806 } 1761 # endif /* VBOX_USB_WITH_ FAM*/1807 # endif /* VBOX_USB_WITH_INOTIFY */ 1762 1808 #endif /* VBOX_USB_WITH_SYSFS */ 1763 1809
Note:
See TracChangeset
for help on using the changeset viewer.