src/gui/embedded/qlock.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qlock_p.h"
       
    43 
       
    44 
       
    45 #ifdef QT_NO_QWS_MULTIPROCESS
       
    46 
       
    47 QT_BEGIN_NAMESPACE
       
    48 
       
    49 /* no multiprocess - use a dummy */
       
    50 
       
    51 QLock::QLock(const QString & /*filename*/, char /*id*/, bool /*create*/)
       
    52     : type(Read), data(0)
       
    53 {
       
    54 }
       
    55 
       
    56 QLock::~QLock()
       
    57 {
       
    58 }
       
    59 
       
    60 bool QLock::isValid() const
       
    61 {
       
    62     return true;
       
    63 }
       
    64 
       
    65 void QLock::lock(Type t)
       
    66 {
       
    67     data = (QLockData *)-1;
       
    68     type = t;
       
    69 }
       
    70 
       
    71 void QLock::unlock()
       
    72 {
       
    73     data = 0;
       
    74 }
       
    75 
       
    76 bool QLock::locked() const
       
    77 {
       
    78     return data;
       
    79 }
       
    80 
       
    81 QT_END_NAMESPACE
       
    82 
       
    83 #else // QT_NO_QWS_MULTIPROCESS
       
    84 
       
    85 #include "qwssignalhandler_p.h"
       
    86 
       
    87 #include <unistd.h>
       
    88 #include <sys/types.h>
       
    89 #if defined(Q_OS_DARWIN)
       
    90 #   define Q_NO_SEMAPHORE
       
    91 #   include <sys/stat.h>
       
    92 #   include <sys/file.h>
       
    93 #else // Q_OS_DARWIN
       
    94 #   include <sys/sem.h>
       
    95 #   if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) && !defined(QT_LINUXBASE)) \
       
    96     || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) \
       
    97     || defined(Q_OS_BSDI)
       
    98         /* union semun is defined by including <sys/sem.h> */
       
    99 #   else
       
   100 /* according to X/OPEN we have to define it ourselves */
       
   101 union semun {
       
   102     int val;                    /* value for SETVAL */
       
   103     struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
       
   104     unsigned short *array;      /* array for GETALL, SETALL */
       
   105 };
       
   106 #   endif
       
   107 #endif // Q_OS_DARWIN
       
   108 #include <sys/ipc.h>
       
   109 #include <string.h>
       
   110 #include <errno.h>
       
   111 #include <qdebug.h>
       
   112 #include <signal.h>
       
   113 
       
   114 #include <private/qcore_unix_p.h> // overrides QT_OPEN
       
   115 
       
   116 
       
   117 QT_BEGIN_NAMESPACE
       
   118 
       
   119 #define MAX_LOCKS   200            // maximum simultaneous read locks
       
   120 
       
   121 class QLockData
       
   122 {
       
   123 public:
       
   124 #ifdef Q_NO_SEMAPHORE
       
   125     QByteArray file;
       
   126 #endif // Q_NO_SEMAPHORE
       
   127     int id;
       
   128     int count;
       
   129     bool owned;
       
   130 };
       
   131 
       
   132 /*!
       
   133     \class QLock
       
   134     \brief The QLock class is a wrapper for a System V shared semaphore.
       
   135 
       
   136     \ingroup qws
       
   137 
       
   138     \internal
       
   139 
       
   140     It is used by \l{Qt for Embedded Linux} for synchronizing access to the graphics
       
   141     card and shared memory region between processes.
       
   142 */
       
   143 
       
   144 /*!
       
   145     \enum QLock::Type
       
   146 
       
   147     \value Read
       
   148     \value Write
       
   149 */
       
   150 
       
   151 /*!
       
   152     \fn QLock::QLock(const QString &filename, char id, bool create)
       
   153 
       
   154     Creates a lock. \a filename is the file path of the Unix-domain
       
   155     socket the \l{Qt for Embedded Linux} client is using. \a id is the name of the
       
   156     particular lock to be created on that socket. If \a create is true
       
   157     the lock is to be created (as the Qt for Embedded Linux server does); if \a
       
   158     create is false the lock should exist already (as the Qt for Embedded Linux
       
   159     client expects).
       
   160 */
       
   161 
       
   162 QLock::QLock(const QString &filename, char id, bool create)
       
   163 {
       
   164     data = new QLockData;
       
   165     data->count = 0;
       
   166 #ifdef Q_NO_SEMAPHORE
       
   167     data->file = QString(filename+id).toLocal8Bit().constData();
       
   168     for(int x = 0; x < 2; x++) {
       
   169         data->id = QT_OPEN(data->file, O_RDWR | (x ? O_CREAT : 0), S_IRWXU);
       
   170         if(data->id != -1 || !create) {
       
   171             data->owned = x;
       
   172             break;
       
   173         }
       
   174     }
       
   175 #else
       
   176     key_t semkey = ftok(filename.toLocal8Bit().constData(), id);
       
   177     data->id = semget(semkey,0,0);
       
   178     data->owned = create;
       
   179     if (create) {
       
   180         semun arg; arg.val = 0;
       
   181         if (data->id != -1)
       
   182             semctl(data->id,0,IPC_RMID,arg);
       
   183         data->id = semget(semkey,1,IPC_CREAT|0600);
       
   184         arg.val = MAX_LOCKS;
       
   185         semctl(data->id,0,SETVAL,arg);
       
   186 
       
   187         QWSSignalHandler::instance()->addSemaphore(data->id);
       
   188     }
       
   189 #endif
       
   190     if (data->id == -1) {
       
   191         int eno = errno;
       
   192         qWarning("Cannot %s semaphore %s '%c'", (create ? "create" : "get"),
       
   193                  qPrintable(filename), id);
       
   194         qDebug() << "Error" << eno << strerror(eno);
       
   195     }
       
   196 }
       
   197 
       
   198 /*!
       
   199     \fn QLock::~QLock()
       
   200 
       
   201     Destroys a lock
       
   202 */
       
   203 
       
   204 QLock::~QLock()
       
   205 {
       
   206     if (locked())
       
   207         unlock();
       
   208 #ifdef Q_NO_SEMAPHORE
       
   209     if(isValid()) {
       
   210         QT_CLOSE(data->id);
       
   211         if(data->owned)
       
   212             unlink(data->file);
       
   213     }
       
   214 #else
       
   215     if(data->owned)
       
   216         QWSSignalHandler::instance()->removeSemaphore(data->id);
       
   217 #endif
       
   218     delete data;
       
   219 }
       
   220 
       
   221 /*!
       
   222     \fn bool QLock::isValid() const
       
   223 
       
   224     Returns true if the lock constructor was successful; returns false if
       
   225     the lock could not be created or was not available to connect to.
       
   226 */
       
   227 
       
   228 bool QLock::isValid() const
       
   229 {
       
   230     return (data->id != -1);
       
   231 }
       
   232 
       
   233 /*!
       
   234     Locks the semaphore with a lock of type \a t. Locks can either be
       
   235     \c Read or \c Write. If a lock is \c Read, attempts by other
       
   236     processes to obtain \c Read locks will succeed, and \c Write
       
   237     attempts will block until the lock is unlocked. If locked as \c
       
   238     Write, all attempts to lock by other processes will block until
       
   239     the lock is unlocked. Locks are stacked: i.e. a given QLock can be
       
   240     locked multiple times by the same process without blocking, and
       
   241     will only be unlocked after a corresponding number of unlock()
       
   242     calls.
       
   243 */
       
   244 
       
   245 void QLock::lock(Type t)
       
   246 {
       
   247     if (!data->count) {
       
   248 #ifdef Q_NO_SEMAPHORE
       
   249         int op = LOCK_SH;
       
   250         if(t == Write)
       
   251             op = LOCK_EX;
       
   252         for(int rv=1; rv;) {
       
   253             rv = flock(data->id, op);
       
   254             if (rv == -1 && errno != EINTR)
       
   255                 qDebug("Semop lock failure %s",strerror(errno));
       
   256         }
       
   257 #else
       
   258         sembuf sops;
       
   259         sops.sem_num = 0;
       
   260         sops.sem_flg = SEM_UNDO;
       
   261 
       
   262         if (t == Write) {
       
   263             sops.sem_op = -MAX_LOCKS;
       
   264             type = Write;
       
   265         } else {
       
   266             sops.sem_op = -1;
       
   267             type = Read;
       
   268         }
       
   269 
       
   270         int rv;
       
   271         do {
       
   272             rv = semop(data->id,&sops,1);
       
   273             if (rv == -1 && errno != EINTR)
       
   274                 qDebug("Semop lock failure %s",strerror(errno));
       
   275         } while (rv == -1 && errno == EINTR);
       
   276 #endif
       
   277     }
       
   278     data->count++;
       
   279 }
       
   280 
       
   281 /*!
       
   282     \fn void QLock::unlock()
       
   283 
       
   284     Unlocks the semaphore. If other processes were blocking waiting to
       
   285     lock() the semaphore, one of them will wake up and succeed in
       
   286     lock()ing.
       
   287 */
       
   288 
       
   289 void QLock::unlock()
       
   290 {
       
   291     if(data->count) {
       
   292         data->count--;
       
   293         if(!data->count) {
       
   294 #ifdef Q_NO_SEMAPHORE
       
   295             for(int rv=1; rv;) {
       
   296                 rv = flock(data->id, LOCK_UN);
       
   297                 if (rv == -1 && errno != EINTR)
       
   298                     qDebug("Semop lock failure %s",strerror(errno));
       
   299             }
       
   300 #else
       
   301             sembuf sops;
       
   302             sops.sem_num = 0;
       
   303             sops.sem_op = 1;
       
   304             sops.sem_flg = SEM_UNDO;
       
   305             if (type == Write)
       
   306                 sops.sem_op = MAX_LOCKS;
       
   307 
       
   308             int rv;
       
   309             do {
       
   310                 rv = semop(data->id,&sops,1);
       
   311                 if (rv == -1 && errno != EINTR)
       
   312                     qDebug("Semop unlock failure %s",strerror(errno));
       
   313             } while (rv == -1 && errno == EINTR);
       
   314 #endif
       
   315         }
       
   316     } else {
       
   317         qDebug("Unlock without corresponding lock");
       
   318     }
       
   319 }
       
   320 
       
   321 /*!
       
   322     \fn bool QLock::locked() const
       
   323 
       
   324     Returns true if the lock is currently held by the current process;
       
   325     otherwise returns false.
       
   326 */
       
   327 
       
   328 bool QLock::locked() const
       
   329 {
       
   330     return (data->count > 0);
       
   331 }
       
   332 
       
   333 QT_END_NAMESPACE
       
   334 
       
   335 #endif // QT_NO_QWS_MULTIPROCESS
       
   336