tests/auto/qsharedmemory/src/qsystemlock_unix.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 test suite 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 
       
    43 #include "qsystemlock.h"
       
    44 #include "qsystemlock_p.h"
       
    45 
       
    46 #include <qdebug.h>
       
    47 #include <qfile.h>
       
    48 
       
    49 #include <sys/types.h>
       
    50 #include <sys/ipc.h>
       
    51 #include <fcntl.h>
       
    52 #include <errno.h>
       
    53 #include <sys/shm.h>
       
    54 #include <unistd.h>
       
    55 
       
    56 #include <sys/sem.h>
       
    57 // We have to define this as on some sem.h will have it
       
    58 union qt_semun {
       
    59     int val;                    /* value for SETVAL */
       
    60     struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
       
    61     unsigned short *array;      /* array for GETALL, SETALL */
       
    62 };
       
    63 
       
    64 #define tr(x) QT_TRANSLATE_NOOP(QLatin1String("QSystemLock"), (x))
       
    65 
       
    66 #if defined(Q_OS_SYMBIAN)
       
    67 int createUnixKeyFile(const QString &fileName)
       
    68 {
       
    69     if (QFile::exists(fileName))
       
    70         return 0;
       
    71 
       
    72     int fd = open(QFile::encodeName(fileName).constData(),
       
    73             O_EXCL | O_CREAT | O_RDWR, 0640);
       
    74     if (-1 == fd) {
       
    75         if (errno == EEXIST)
       
    76             return 0;
       
    77         return -1;
       
    78     } else {
       
    79         close(fd);
       
    80     }
       
    81     return 1;
       
    82 }
       
    83 #endif
       
    84 
       
    85 QSystemLockPrivate::QSystemLockPrivate() :
       
    86         semaphore(-1), lockCount(0),
       
    87         error(QSystemLock::NoError), unix_key(-1), createdFile(false), createdSemaphore(false)
       
    88 {
       
    89 }
       
    90 
       
    91 void QSystemLockPrivate::setErrorString(const QString &function)
       
    92 {
       
    93     switch (errno) {
       
    94     case EIDRM:
       
    95         errorString = function + QLatin1String(": ") + tr("The semaphore set was removed");
       
    96         error = QSystemLock::UnknownError;
       
    97         break;
       
    98     default:
       
    99         errorString = function + QLatin1String(": ") + tr("unknown error");
       
   100         error = QSystemLock::UnknownError;
       
   101         qWarning() << errorString << "key" << key << "errno" << errno << ERANGE << ENOMEM << EINVAL << EINTR << EFBIG << EFAULT << EAGAIN << EACCES << E2BIG;
       
   102     }
       
   103 }
       
   104 
       
   105 /*!
       
   106     \internal
       
   107 
       
   108     Setup unix_key
       
   109  */
       
   110 key_t QSystemLockPrivate::handle()
       
   111 {
       
   112     if (key.isEmpty())
       
   113         return -1;
       
   114 
       
   115     // ftok requires that an actual file exists somewhere
       
   116     // If we have already made at some point in the past,
       
   117     // double check that it is still there.
       
   118     if (-1 != unix_key) {
       
   119         int aNewunix_key = ftok(QFile::encodeName(fileName).constData(), 'Q');
       
   120         if (aNewunix_key != unix_key) {
       
   121             cleanHandle();
       
   122         } else {
       
   123             return unix_key;
       
   124         }
       
   125     }
       
   126 
       
   127     // Create the file needed for ftok
       
   128 #if defined(Q_OS_SYMBIAN)
       
   129     int built = createUnixKeyFile(fileName);
       
   130 #else
       
   131     int built = QSharedMemoryPrivate::createUnixKeyFile(fileName);
       
   132 #endif
       
   133     if (-1 == built)
       
   134         return -1;
       
   135     createdFile = (1 == built);
       
   136 
       
   137     // Get the unix key for the created file
       
   138     unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q');
       
   139     if (-1 == unix_key) {
       
   140         setErrorString(QLatin1String("QSystemLock::handle ftok"));
       
   141         return -1;
       
   142     }
       
   143 
       
   144     // Get semaphore
       
   145     semaphore = semget(unix_key, 1, 0666 | IPC_CREAT | IPC_EXCL);
       
   146     if (-1 == semaphore) {
       
   147         if (errno == EEXIST)
       
   148             semaphore = semget(unix_key, 1, 0666 | IPC_CREAT);
       
   149         if (-1 == semaphore) {
       
   150             setErrorString(QLatin1String("QSystemLock::handle semget"));
       
   151             cleanHandle();
       
   152             return -1;
       
   153         }
       
   154     } else {
       
   155         // Created semaphore, initialize value.
       
   156         createdSemaphore = true;
       
   157         qt_semun init_op;
       
   158         init_op.val = MAX_LOCKS;
       
   159         if (-1 == semctl(semaphore, 0, SETVAL, init_op)) {
       
   160             setErrorString(QLatin1String("QSystemLock::handle semctl"));
       
   161             cleanHandle();
       
   162             return -1;
       
   163         }
       
   164     }
       
   165 
       
   166     return unix_key;
       
   167 }
       
   168 
       
   169 /*!
       
   170     \internal
       
   171 
       
   172     Cleanup the unix_key
       
   173  */
       
   174 void QSystemLockPrivate::cleanHandle()
       
   175 {
       
   176     unix_key = -1;
       
   177 
       
   178     // remove the file if we made it
       
   179     if (createdFile) {
       
   180         if (!QFile::remove(fileName))
       
   181             setErrorString(QLatin1String("QSystemLock::cleanHandle QFile::remove"));
       
   182         createdFile = false;
       
   183     }
       
   184 
       
   185     if (createdSemaphore) {
       
   186         if (-1 != semaphore) {
       
   187             if (-1 == semctl(semaphore, 0, IPC_RMID)) {
       
   188                 setErrorString(QLatin1String("QSystemLock::cleanHandle semctl"));
       
   189             }
       
   190             semaphore = -1;
       
   191         }
       
   192         createdSemaphore = false;
       
   193     }
       
   194 }
       
   195 
       
   196 /*!
       
   197     \internal
       
   198 
       
   199     modifySemaphore generates operation.sem_op and handles recursive behavior.
       
   200  */
       
   201 bool QSystemLockPrivate::modifySemaphore(QSystemLockPrivate::Operation op,
       
   202         QSystemLock::LockMode mode)
       
   203 {
       
   204     if (-1 == handle())
       
   205         return false;
       
   206 
       
   207     if ((lockCount == 0 && op == Lock) || (lockCount > 0 && op == Unlock)) {
       
   208         if (op == Unlock) {
       
   209             --lockCount;
       
   210             Q_ASSERT(lockCount >= 0);
       
   211             if (lockCount > 0)
       
   212                 return true;
       
   213         }
       
   214 
       
   215         struct sembuf operation;
       
   216         operation.sem_num = 0;
       
   217         operation.sem_op = (mode == QSystemLock::ReadWrite) ? MAX_LOCKS : 1;
       
   218         if (op == Lock)
       
   219             operation.sem_op *= -1;
       
   220         operation.sem_flg = SEM_UNDO;
       
   221 
       
   222         if (-1 == semop(semaphore, &operation, 1)) {
       
   223             setErrorString(QLatin1String("QSystemLock::modify"));
       
   224             return false;
       
   225         }
       
   226         lockedMode = mode;
       
   227     }
       
   228     if (op == Lock)
       
   229         lockCount++;
       
   230 
       
   231     return true;
       
   232 }
       
   233