public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Concurrent access to /dev/urandom
@ 2004-11-27 20:45 Bernard Normier
  2004-11-27 20:56 ` Jan Engelhardt
  2004-11-29 22:47 ` Jon Masters
  0 siblings, 2 replies; 39+ messages in thread
From: Bernard Normier @ 2004-11-27 20:45 UTC (permalink / raw)
  To: linux-kernel

I use /dev/urandom to generate UUIDs by reading 16 random bytes from
/dev/urandom (very much like e2fsprogs' libuuid).

As long as I serialize access to /dev/urandom, I get different values.
However, with concurrent access to /dev/urandom, I quickly get duplicate
values. libuuid uses one shared file descriptor for all threads, while
the test case below uses a file descriptor per read; it does not appear
to change anything ... duplicates appear very quickly (within seconds).
I tried on 2.4.20-27.9smp, 2.6.8-1.521smp, 2.6.9-1.6_FC2smp.

Within one process, I could easily serialize access to /dev/urandom to
avoid this problem. But I suspect the same would happen with concurrent
access from different processes, and I'd rather avoid interprocess
synchronization. Is this the expected behavior of /dev/urandom? Any
suggestions on how to get unique values?

Thanks,
Bernard

#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <iostream>
#include <set>

using namespace std;

static pthread_mutex_t staticMutex = PTHREAD_MUTEX_INITIALIZER;

struct Key
{
    long long high;
    long long low;
};

struct KeyComp
{
    inline bool operator()(const Key& lhs, const Key& rhs)
    {
 return lhs.high < rhs.high || (lhs.high == rhs.high && lhs.low < rhs.low);
    }
};

static set<Key, KeyComp> keySet;
static int keyCount;


void* threadFailed()
{
    return reinterpret_cast<void*>(-1);
}

extern "C"
void* readRandom(void* d)
{
    int threadId = reinterpret_cast<int>(d);

    for(int i = 0; i < keyCount; ++i)
    {
 int fd = open("/dev/urandom", O_RDONLY);

 if (fd == -1)
 {
     cerr << "could not open /dev/urandom" << endl;
     return threadFailed();
 }

 int reads = 0;
 size_t index = 0;
 char buffer[16];

 while(reads <= 20 && index != sizeof(Key))
 {
     ssize_t bytesRead = read(fd, buffer + index, sizeof(Key) - index);

     if(bytesRead == -1)
     {
  if(errno != EINTR)
  {
      int err = errno;
      cerr << "Reading /dev/urandom returned " << strerror(err) << endl;
      close(fd);
      return threadFailed();
  }
     }
     else
     {
  index += bytesRead;
  reads++;
     }
 }

 if(index != sizeof(buffer))
 {
     close(fd);
     cerr << "Giving up after 20 reads!" << endl;
     return threadFailed();
 }

 close(fd);

 int err = pthread_mutex_lock(&staticMutex);
 if(err != 0)
 {
     cerr << "pthread_mutex_lock failed" << endl;
     return threadFailed();
 }

 Key& key = reinterpret_cast<Key&>(buffer);

 pair<set<Key, KeyComp>::iterator, bool> result = keySet.insert(key);
 if(!result.second)
 {
     cerr << "******** Found duplicate!! **********" << endl;
     struct AsInts
     {
  unsigned int x1;
  unsigned int x2;
  unsigned int x3;
  unsigned int x4;
     };

     AsInts& ints = reinterpret_cast<AsInts&>(buffer);
     cerr << hex << ints.x1 << "-" << ints.x2 << "-" << ints.x3 << "-" << 
ints.x4 << endl;

     pthread_mutex_unlock(&staticMutex);
     return threadFailed();
 }

 if(i > 0 && (i % 100000 == 0))
 {
     cout << "Thread " << threadId << ": read " << i << " keys" << endl;
 }

 err = pthread_mutex_unlock(&staticMutex);
 if(err != 0)
 {
     cerr << "pthread_mutex_unlock failed" << endl;
     return threadFailed();
 }
    }

    return 0;
}

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
 cerr << "Usage: " << argv[0] << " [number of keys to read] [number of 
threads]" << endl;
 return -1;
    }

    int howMany = atoi(argv[1]);
    int threadCount = atoi(argv[2]);
    keyCount = howMany / threadCount;

    pthread_t* threads = new pthread_t[threadCount];

    for(int i = 0; i < threadCount; ++i)
    {
 int err = pthread_create(&threads[i], 0, readRandom, 
reinterpret_cast<void*>(i));
 if(err != 0)
 {
     cerr << "pthread_create failed" << endl;
     return -1;
 }
    }

    for(int i = 0; i < threadCount; ++i)
    {
 void* threadStatus;
 int err = pthread_join(threads[i], &threadStatus);
 if(err != 0)
 {
     cerr << "pthread_join failed" << endl;
     return -1;
 }
 if(threadStatus != 0)
 {
     cerr << "Thread " << i << " failed" << endl;
     return -1;
 }
    }

    delete[] threads;
    return 0;
}

// build with  g++ -D_REENTRANT  -o utest utest.cpp -lpthread




^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2004-12-12 16:20 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-11-27 20:45 Concurrent access to /dev/urandom Bernard Normier
2004-11-27 20:56 ` Jan Engelhardt
2004-11-27 21:15   ` Bernard Normier
2004-11-27 21:22     ` Jan Engelhardt
2004-11-28 20:58       ` Bernard Normier
2004-12-07 23:41         ` Bernard Normier
2004-12-08  1:28           ` Theodore Ts'o
2004-12-08  1:56             ` Bernard Normier
2004-12-08 19:21               ` Theodore Ts'o
2004-12-08 20:15                 ` Bernard Normier
2004-12-08 21:56                 ` Matt Mackall
2004-12-09  1:57                   ` Theodore Ts'o
2004-12-09  2:46                     ` andyliu
2004-12-09  4:55                       ` Matt Mackall
2004-12-09  2:58                     ` Matt Mackall
2004-12-09 21:29                     ` Matt Mackall
2004-12-10  4:47                       ` Matt Mackall
2004-12-10 16:35                         ` Theodore Ts'o
2004-12-10 18:28                           ` Matt Mackall
2004-12-10 21:28                             ` Theodore Ts'o
2004-12-10 22:23                               ` Matt Mackall
2004-12-11  0:22                                 ` Adam Heath
2004-12-11  1:10                                   ` Matt Mackall
2004-12-11 17:33                                   ` Theodore Ts'o
2004-12-11 19:58                                     ` Adam Heath
2004-12-11 20:40                                       ` Matt Mackall
2004-12-12 16:19                                     ` Pavel Machek
2004-12-11  0:19                               ` Adam Heath
2004-12-09  3:10               ` David Lang
2004-12-09  4:52                 ` Matt Mackall
2004-12-09  6:36                 ` Theodore Ts'o
2004-11-29 22:47 ` Jon Masters
2004-11-29 23:14   ` Bernard Normier
2004-11-29 23:43     ` Sven-Haegar Koch
2004-11-30  2:31       ` David Schwartz
2004-11-30  4:14         ` Kyle Moffett
2004-11-30  8:23           ` Jan Engelhardt
2004-11-30 18:50             ` David Schwartz
2004-11-29 23:42   ` David Wagner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox