VirtualBox

Changeset 28882 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Apr 28, 2010 11:17:52 PM (15 years ago)
Author:
vboxsync
Message:

Main/HostHardwareLinux: use inotify instead of FAM for USB hotplug probing, and disable the hal/dbus method for now to get testing

Location:
trunk/src/VBox/Main
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r28802 r28882  
    220220        $(if $(VBOX_WITH_DBUS),$(if $(VBOX_USB_WITH_DBUS),VBOX_USB_WITH_DBUS,),) \
    221221        $(if $(VBOX_USB_WITH_SYSFS),VBOX_USB_WITH_SYSFS,) \
    222         $(if $(VBOX_USB_WITH_FAM),VBOX_USB_WITH_FAM,) \
     222        $(if $(VBOX_USB_WITH_INOTIFY),VBOX_USB_WITH_INOTIFY,) \
    223223        $(if $(VBOX_WITH_LIVE_MIGRATION),VBOX_WITH_LIVE_MIGRATION,) \
    224224        $(if $(VBOX_WITH_VUSB),VBOX_WITH_VUSB,)
     
    274274 VBoxSVC_LIBS.solaris += \
    275275        devinfo
    276  ifdef VBOX_USB_WITH_FAM
    277   VBoxSVC_LIBS.linux += \
    278         fam
    279  endif
    280276endif
    281277
  • trunk/src/VBox/Main/include/HostHardwareLinux.h

    r28800 r28882  
    176176{
    177177public:
    178     VBoxMainHotplugWaiterImpl (void) {}
    179     virtual ~VBoxMainHotplugWaiterImpl (void) {}
     178    VBoxMainHotplugWaiterImpl(void) {}
     179    virtual ~VBoxMainHotplugWaiterImpl(void) {}
    180180    /** @copydoc VBoxMainHotplugWaiter::Wait */
    181     virtual int Wait (RTMSINTERVAL cMillies) = 0;
     181    virtual int Wait(RTMSINTERVAL cMillies) = 0;
    182182    /** @copydoc VBoxMainHotplugWaiter::Interrupt */
    183     virtual void Interrupt (void) = 0;
     183    virtual void Interrupt(void) = 0;
     184    /** @copydoc VBoxMainHotplugWaiter::getStatus */
     185    virtual int getStatus(void) = 0;
    184186};
    185187
     
    225227        mImpl->Interrupt();
    226228    }
     229
     230    int getStatus(void)
     231    {
     232        return mImpl ? mImpl->getStatus() : VERR_NO_MEMORY;
     233    }
    227234};
    228235
  • trunk/src/VBox/Main/linux/HostHardwareLinux.cpp

    r28847 r28882  
    77
    88/*
    9  * Copyright (C) 2008 Oracle Corporation
     9 * Copyright (C) 2008-2010 Oracle Corporation
    1010 *
    1111 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1616 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
    1717 * 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.
    1822 */
    1923
     
    4044#include <iprt/param.h>
    4145#include <iprt/path.h>
    42 #include <iprt/pipe.h>
    43 #include <iprt/poll.h>
    44 #include <iprt/socket.h>
    4546#include <iprt/string.h>
    4647#include <iprt/thread.h>  /* for RTThreadSleep() */
     
    5455
    5556#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>
    5863# endif
    5964#endif
     
    9398                                 bool *pfSuccess);
    9499#ifdef VBOX_USB_WITH_SYSFS
    95 # ifdef VBOX_USB_WITH_FAM
     100# ifdef VBOX_USB_WITH_INOTIFY
    96101static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, bool *pfSuccess);
     102
     103/** Function object to be invoked on filenames from a directory. */
     104class 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;
     109public:
     110    bool doHandle(const char *pcszNode)
     111    {
     112        AssertPtr(pcszNode);
     113        Assert(pcszNode[0] == '/');
     114        return handle(pcszNode);
     115    }
     116};
     117
     118static int walkDirectory(const char *pcszPath, pathHandler *pHandler,
     119                         bool useRealPath);
     120static int getDeviceInfoFromSysfs(const char *pcszPath, pathHandler *pHandler);
    97121# endif
    98122# ifdef VBOX_USB_WITH_DBUS
     
    10401064            success = halSuccess;
    10411065# endif /* VBOX_USB_WITH_DBUS */
    1042 # ifdef VBOX_USB_WITH_FAM
     1066# ifdef VBOX_USB_WITH_INOTIFY
    10431067        if (   RT_SUCCESS(rc)
    10441068            && (!success || testing()))
     
    10671091    /** A flag to say that we wish to interrupt the current wait. */
    10681092    volatile bool mInterrupt;
     1093    /** The constructor "return code" */
     1094    int mStatus;
    10691095
    10701096public:
    10711097    /** Test whether this implementation can be used on the current system */
    1072     static bool HalAvailable(void)
     1098    static bool Available(void)
    10731099    {
    10741100        RTMemAutoPtr<DBusConnection, VBoxHalShutdown> dbusConnection;
     
    10871113    /** @copydoc VBoxMainHotplugWaiter::Interrupt */
    10881114    virtual void Interrupt (void);
     1115    /** @copydoc VBoxMainHotplugWaiter::getStatus */
     1116    virtual int getStatus(void)
     1117    {
     1118        return mStatus;
     1119    }
    10891120};
    10901121
     
    10951126hotplugDBusImpl::hotplugDBusImpl (void) : mTriggered(false), mInterrupt(false)
    10961127{
    1097     int rc = VINF_SUCCESS;
    1098 
    1099     if (RT_SUCCESS(RTDBusLoadLib()))
     1128    int rc;
     1129
     1130    if (RT_SUCCESS(rc = RTDBusLoadLib()))
    11001131    {
    11011132        for (unsigned i = 0; RT_SUCCESS(rc) && i < 5 && !mConnection; ++i)
     
    11171148            mConnection.reset();
    11181149    }
     1150    mStatus = rc;
    11191151}
    11201152
     
    11781210    /** @copydoc VBoxMainHotplugWaiter::Interrupt */
    11791211    virtual void Interrupt (void) {}
     1212    virtual int getStatus(void)
     1213    {
     1214        return VERR_NOT_SUPPORTED;
     1215    }
     1216
    11801217};
    11811218
    11821219#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. */
     1224class 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
     1237public:
     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
     1263int 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
     1305bool 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}
    11841315
    11851316# define SYSFS_USB_DEVICE_PATH "/dev/bus/usb"
    11861317# define SYSFS_WAKEUP_STRING "Wake up!"
    11871318
    1188 class hotplugSysfsFAMImpl : public VBoxMainHotplugWaiterImpl
     1319class hotplugInotifyImpl : public VBoxMainHotplugWaiterImpl
    11891320{
    11901321    /** Pipe used to interrupt wait(), the read end. */
    1191     RTPIPE mhWakeupPipeR;
     1322    int mhWakeupPipeR;
    11921323    /** 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;
    12021327    /** Flag to mark that the Wait() method is currently being called, and to
    12031328     * ensure that it isn't called multiple times in parallel. */
    1204     uint32_t mfWaiting;
     1329    volatile uint32_t mfWaiting;
    12051330    /** iprt result code from object initialisation.  Should be AssertReturn-ed
    12061331     * on at the start of all methods.  I went this way because I didn't want
     
    12111336    enum
    12121337    {
    1213         RPIPE_ID = 1,
    1214         FAMFD_ID
     1338        RPIPE_ID = 0,
     1339        INOTIFY_ID,
     1340        MAX_POLLID
    12151341    };
    1216 
    1217     /** Initialise the connection to the FAM daemon, allocating all required
    1218      * resources.
    1219      * @returns iprt status code
    1220      */
    1221     int initConnection(void);
    1222 
    1223     /** Clean up the connection to the FAM daemon, freeing any allocated
    1224      * resources and gracefully skipping over any which have not yet been
    1225      * allocated or already cleaned up.
    1226      * @returns iprt status code
    1227      */
    1228     void termConnection(void);
    12291342
    12301343    /** Clean up any resources in use, gracefully skipping over any which have
     
    12331346    void term(void);
    12341347
    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();
    13041349
    13051350    /** Read the wakeup string from the wakeup pipe */
    13061351    int drainWakeupPipe(void);
    13071352public:
    1308     hotplugSysfsFAMImpl(void);
    1309     virtual ~hotplugSysfsFAMImpl(void)
     1353    hotplugInotifyImpl(void);
     1354    virtual ~hotplugInotifyImpl(void)
    13101355    {
    13111356        term();
     
    13161361#endif
    13171362    }
    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
    13241376    /** @copydoc VBoxMainHotplugWaiter::Wait */
    13251377    virtual int Wait(RTMSINTERVAL);
     
    13281380};
    13291381
    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 */
     1383static 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
     1405hotplugInotifyImpl::hotplugInotifyImpl(void) :
     1406    mhWakeupPipeR(-1), mhWakeupPipeW(-1), mfWaiting(0),
     1407    mStatus(VERR_WRONG_ORDER)
    13341408{
    13351409#  ifdef DEBUG
     
    13421416    if (!testing())
    13431417    {
    1344 #   ifndef VBOX_WITH_SYSFS_BY_DEFAULT
    1345         /** @todo only create this object if we will use it */
    1346         // Assert(!RTFileExists("/proc/bus/usb/devices"));
    1347 #   endif
    13481418#   ifdef VBOX_USB_WITH_DBUS
    1349         Assert(!hotplugDBusImpl::HalAvailable());
     1419        Assert(!hotplugDBusImpl::Available());
    13501420#   endif
    13511421    }
     
    13531423    int rc;
    13541424    do {
    1355         if (RT_FAILURE(rc = RTPipeCreate(&mhWakeupPipeR, &mhWakeupPipeW, 0)))
     1425        if (RT_FAILURE(rc = mWatches.getStatus()))
    13561426            break;
    1357         if (RT_FAILURE(rc = initConnection()))
     1427        mWatches.doHandle(SYSFS_USB_DEVICE_PATH);
     1428        if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW)))
    13581429            break;
    1359 #  ifdef DEBUG
    1360         /** Other tests */
    1361         testMonitorDirectoryFAM();
    1362         testNextEventFAM();
    1363         testCheckConnection();
    1364 #  endif
    13651430    } while(0);
    13661431    mStatus = rc;
     
    13691434}
    13701435
    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)
     1436void hotplugInotifyImpl::term(void)
    14291437{
    14301438    /** This would probably be a pending segfault, so die cleanly */
    14311439    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
     1446int 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
     1464int 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);
    14451472    return VINF_SUCCESS;
    14461473}
    14471474
    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;
     1475int hotplugInotifyImpl::Wait(RTMSINTERVAL aMillies)
     1476{
    14611477    int rc;
    1462     FAMEvent ev;
    1463 
     1478
     1479    AssertRCReturn(mStatus, VERR_WRONG_ORDER);
    14641480    bool fEntered = ASMAtomicCmpXchgU32(&mfWaiting, 1, 0);
    14651481    AssertReturn(fEntered, VERR_WRONG_ORDER);
    14661482    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)))
    14681487            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;
    14711504            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))
    14751513            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()))
    14791516            break;
    1480         rc = sysfsGetStatusForFAMCode(ev.code);
    14811517    } while (false);
    14821518    mfWaiting = 0;
    1483     /* If at all, this should only get called once. */
    1484     AssertLogRelMsg(   RT_SUCCESS(rc)
    1485                     || rc == VERR_TRY_AGAIN
    1486                     || rc == VERR_FAM_OPEN_FAILED
    1487                     || rc == VERR_TIMEOUT, ("rc = %Rrc\n", rc));
    14881519    return rc;
    14891520}
    14901521
    1491 void hotplugSysfsFAMImpl::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 */
     1522void 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 */
    15011532#endif  /* VBOX_USB_WTH_SYSFS */
    15021533
    15031534VBoxMainHotplugWaiter::VBoxMainHotplugWaiter(void)
    15041535{
     1536    try
     1537    {
    15051538#ifdef VBOX_USB_WITH_SYSFS
    1506 # ifdef VBOX_USB_WITH_DBUS
    1507     if (hotplugDBusImpl::HalAvailable())
    1508     {
    1509         mImpl = new hotplugDBusImpl;
    1510         return;
    1511     }
    1512 # endif  /* VBOX_USB_WITH_DBUS */
    1513 # ifdef VBOX_USB_WITH_FAM
    1514     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 */
    15201553#endif  /* VBOX_USB_WITH_SYSFS */
    1521     mImpl = new hotplugNullImpl;
     1554        mImpl = new hotplugNullImpl;
     1555    }
     1556    catch(std::bad_alloc &e)
     1557    { }
    15221558}
    15231559
    15241560#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
    15441564 * @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.
    15481570 *
    15491571 * @returns IPRT status code
    15501572 */
    15511573/* static */
    1552 int getDeviceInfoFromSysfs(const char *pcszPath, sysfsPathHandler *pHandler)
     1574int walkDirectory(const char *pcszPath, pathHandler *pHandler, bool useRealPath)
    15531575{
    15541576    AssertPtrReturn(pcszPath, VERR_INVALID_POINTER);
     
    15591581
    15601582    rc = RTDirOpen(&pDir, pcszPath);
    1561     AssertRCReturn(rc, rc);
     1583    if (RT_FAILURE(rc))
     1584        return rc;
    15621585    while (RT_SUCCESS(rc))
    15631586    {
     
    15771600        if (RT_FAILURE(rc))
    15781601            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;
    15831612    }
    15841613    RTDirClose(pDir);
     
    15901619
    15911620
     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 */
     1632int getDeviceInfoFromSysfs(const char *pcszPath, pathHandler *pHandler)
     1633{
     1634    return walkDirectory(pcszPath, pHandler, true);
     1635}
     1636
     1637
    15921638#define USBDEVICE_MAJOR 189
    15931639
     
    16161662 * interface.  To be used with getDeviceInfoFromSysfs().
    16171663 */
    1618 class matchUSBDevice : public sysfsPathHandler
     1664class matchUSBDevice : public pathHandler
    16191665{
    16201666    USBDeviceInfoList *mList;
     
    16571703 * device.  To be used with getDeviceInfoFromSysfs().
    16581704 */
    1659 class matchUSBInterface : public sysfsPathHandler
     1705class matchUSBInterface : public pathHandler
    16601706{
    16611707    USBDeviceInfo *mInfo;
     
    17591805    return rc;
    17601806}
    1761 # endif /* VBOX_USB_WITH_FAM */
     1807# endif /* VBOX_USB_WITH_INOTIFY */
    17621808#endif /* VBOX_USB_WITH_SYSFS */
    17631809
  • trunk/src/VBox/Main/testcase/Makefile.kmk

    r28800 r28882  
    130130        $(if $(VBOX_WITH_DBUS),$(if $(VBOX_USB_WITH_DBUS),VBOX_USB_WITH_DBUS,),) \
    131131        $(if $(VBOX_USB_WITH_SYSFS),VBOX_USB_WITH_SYSFS,) \
    132         $(if $(VBOX_USB_WITH_FAM),VBOX_USB_WITH_FAM,)
     132        $(if $(VBOX_USB_WITH_INOTIFY),VBOX_USB_WITH_INOTIFY,)
    133133tstHostHardwareLinux_LIBS     += \
    134         $(PATH_OUT)/lib/USBLib.a \
    135         $(if $(VBOX_USB_WITH_FAM),fam,)
     134        $(PATH_OUT)/lib/USBLib.a
    136135
    137136
  • trunk/src/VBox/Main/testcase/tstHostHardwareLinux.cpp

    r28800 r28882  
    3535#include <stdlib.h>
    3636
    37 void doHotplugEvent(VBoxMainHotplugWaiter *waiter, RTMSINTERVAL cMillies)
     37int doHotplugEvent(VBoxMainHotplugWaiter *waiter, RTMSINTERVAL cMillies)
    3838{
     39    int rc;
    3940    while (true)
    4041    {
    41         int rc = waiter->Wait (cMillies);
    42         if (rc == VERR_TRY_AGAIN)
    43         {
    44             RTThreadYield();
    45             continue;
    46         }
    47         if (rc == VERR_TIMEOUT)
     42        rc = waiter->Wait (cMillies);
     43        if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
    4844            break;
    4945        if (RT_FAILURE(rc))
     
    5551            break;
    5652    }
     53    return rc;
    5754}
    5855
     
    154151    RTPrintf ("Waiting for a hotplug event, Ctrl-C to abort...\n");
    155152    doHotplugEvent(&waiter, RT_INDEFINITE_WAIT);
     153    RTPrintf ("Testing interrupting a hotplug event...\n");
     154    waiter.Interrupt();
     155    rc = doHotplugEvent(&waiter, 5000);
     156    RTPrintf ("%s\n", rc == VERR_INTERRUPTED ? "Success!" : "Failed!");
    156157#endif  /* VBOX_USB_WITH_SYSFS */
    157158    return 0;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette