From: "Bernard Normier" <bernard@zeroc.com>
To: <linux-kernel@vger.kernel.org>
Subject: Concurrent access to /dev/urandom
Date: Sat, 27 Nov 2004 15:45:49 -0500 [thread overview]
Message-ID: <006001c4d4c2$14470880$6400a8c0@centrino> (raw)
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
next reply other threads:[~2004-11-27 20:48 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-27 20:45 Bernard Normier [this message]
2004-11-27 20:56 ` Concurrent access to /dev/urandom 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='006001c4d4c2$14470880$6400a8c0@centrino' \
--to=bernard@zeroc.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.