Below is the list of changes that have just been committed into a local
5.1 repository of msvensson. When msvensson does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-03-26 11:53:01+02:00, msvensson@stripped +5 -0
Add unittest for mf_tempfile
include/Makefile.am@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +1 -1
Add my_vector.h and ThreadRunner.h
include/ThreadRunner.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +232 -0
Add helper class for easily testing with multiple threads
include/ThreadRunner.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +0 -0
include/my_vector.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +139 -0
Add helper class for maintaining a dynamic list
include/my_vector.h@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +0 -0
mysys/my_winthread.c@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped +4 -3
Update windows implementation of 'pthread_create' to allow
"attr" argument to be NULL
unittest/mysys/mf_tempfile-t.cc@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped
+104 -0
Add mf_tempfile-t unit test program for mf_tempfile
unittest/mysys/mf_tempfile-t.cc@stripped, 2007-03-26 11:53:00+02:00, msvensson@stripped
+0 -0
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: msvensson
# Host: pilot.blaudden
# Root: /home/msvensson/mysql/bug26233/my51-bug26233
--- 1.77/include/Makefile.am 2006-12-31 01:06:32 +01:00
+++ 1.78/include/Makefile.am 2007-03-26 11:53:00 +02:00
@@ -37,7 +37,7 @@ noinst_HEADERS = config-win.h config-net
mysql_version.h.in my_handler.h my_time.h decimal.h \
my_vle.h my_user.h my_atomic.h atomic/nolock.h \
atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \
- my_libwrap.h
+ my_libwrap.h my_vector.h ThreadRunner.h
# Remove built files and the symlinked directories
CLEANFILES = $(BUILT_SOURCES) readline openssl
--- 1.13/mysys/my_winthread.c 2006-12-23 20:04:08 +01:00
+++ 1.14/mysys/my_winthread.c 2007-03-26 11:53:00 +02:00
@@ -78,11 +78,11 @@ int pthread_create(pthread_t *thread_id,
pthread_mutex_lock(&THR_LOCK_thread);
#ifdef __BORLANDC__
hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
- attr->dwStackSize ? attr->dwStackSize :
+ attr && attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
#else
hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
- attr->dwStackSize ? attr->dwStackSize :
+ attr && attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
#endif
DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
@@ -96,7 +96,8 @@ int pthread_create(pthread_t *thread_id,
("Can't create thread to handle request (error %d)",error));
DBUG_RETURN(error ? error : -1);
}
- VOID(SetThreadPriority(hThread, attr->priority)) ;
+ VOID(SetThreadPriority(hThread,
+ attr && attr->priority ? attr->priority : 0));
DBUG_RETURN(0);
}
--- New file ---
+++ include/ThreadRunner.h 07/03/26 11:53:00
#include <my_global.h>
#include <my_sys.h>
#include <my_vector.h>
#include <my_pthread.h>
#include <m_string.h>
#ifndef MYSQL_THREAD_RUNNER_H
#define MYSQL_THREAD_RUNNER_H
struct ThreadContext {
my_thread_id tid;
ThreadContext() {};
~ThreadContext() {};
};
pthread_handler_t run_thread(void* arg);
typedef int (thread_runner_func)(ThreadContext* ctx);
class ThreadRunner {
// friend pthread_handler(run_thread);
public:
enum ThreadStatus {
TR_UNDEFINED,
TR_STARTED,
TR_COMPLETED,
};
class Thread {
public:
Thread(ThreadRunner* _parent,
thread_runner_func* _func) :
parent(_parent), func(_func), result(0), status(TR_UNDEFINED) { }
~Thread() {};
void completed(int res)
{
result= res;
status= TR_COMPLETED;
parent->completed();
}
ThreadRunner* parent;
thread_runner_func* func;
pthread_t handle;
int result;
ThreadStatus status;
ThreadContext context;
};
public:
ThreadRunner(unsigned _max_time= 0) :
threads_completed(0), max_time(_max_time)
{
my_init();
pthread_mutex_init(&wait_threads_mutex, MY_MUTEX_INIT_SLOW);
pthread_cond_init(&wait_threads_cond, NULL);
};
~ThreadRunner()
{
clear();
pthread_mutex_destroy(&wait_threads_mutex);
pthread_cond_destroy(&wait_threads_cond);
my_end(MY_CHECK_ERROR);
};
/* Add function to be run in thread */
int add(thread_runner_func* func,
unsigned count);
/* Start all threads and wait for them to return */
int execute();
/* Start threads */
int start();
/* Wait for started threads to return */
int wait();
/* Set max time for threads to run */
int set_max_time(unsigned max_seconds);
/* Check if all threads returned specified error */
bool error(int err){
bool result= true;
for (unsigned i= 0; i < threads.size(); i++)
{
if (threads[i]->result != err)
{
fprintf(stderr, "thread %d failed\n", i);
result= false;
}
}
return result;
}
/* Check if all threads returned sucess */
bool ok(){
return error(0);
}
void clear(){
for (unsigned i= 0; i < threads.size(); i++)
delete threads[i];
threads.clear();
}
private:
Vector<Thread*> threads;
pthread_mutex_t wait_threads_mutex;
pthread_cond_t wait_threads_cond;
unsigned threads_completed;
unsigned max_time;
/*
Called by thread when it has completed
Count number of completed threads and
signal cond if this was the last
*/
void completed()
{
pthread_mutex_lock(&wait_threads_mutex);
threads_completed++;
if(threads_completed == threads.size())
pthread_cond_signal(&wait_threads_cond);
pthread_mutex_unlock(&wait_threads_mutex);
}
};
int ThreadRunner::add(thread_runner_func* func,
unsigned count)
{
for (unsigned i= 0; i < count; i++)
{
Thread* thread= new Thread(this, func);
threads.push_back(thread);
}
return 0;
}
int ThreadRunner::execute()
{
if (start())
return 1;
if(wait())
return 1;
return 0;
}
pthread_handler_t run_thread(void* arg)
{
ThreadRunner::Thread* thread= (ThreadRunner::Thread*)arg;
my_thread_init();
thread->context.tid= my_thread_dbug_id();
int res= thread->func(&thread->context);
thread->completed(res);
my_thread_end();
return 0;
}
int ThreadRunner::start()
{
int result= 0;
pthread_mutex_lock(&wait_threads_mutex);
threads_completed= 0;
for (unsigned i = 0; i < threads.size(); i++)
{
Thread* thread= threads[i];
if (pthread_create(&thread->handle,
NULL,
run_thread,
(void*)thread) != 0)
{
fprintf(stderr, "Could not create thread %d\n", i);
result= 1;
break;
}
thread->status= TR_STARTED;
thread->result= -1;
}
pthread_mutex_unlock(&wait_threads_mutex);
return result;
}
int ThreadRunner::wait()
{
pthread_mutex_lock(&wait_threads_mutex);
while(threads_completed < threads.size())
pthread_cond_wait(&wait_threads_cond,
&wait_threads_mutex);
DBUG_ASSERT(threads_completed == threads.size());
pthread_mutex_unlock(&wait_threads_mutex);
#ifdef __WIN__
/*
All threads have signaled their completion
and called '_threadend' from 'pthread_exit'.
Thus the thread handle is closed and it's
not possible to join the thread
*/
#else
for(unsigned i= 0; i < threads.size(); i++)
{
void* unused;
Thread* thread= threads[i];
pthread_join(thread->handle, &unused);
}
#endif
return 0;
}
template class Vector<ThreadRunner::Thread*>;
#endif
--- New file ---
+++ include/my_vector.h 07/03/26 11:53:00
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef MYSQL_VECTOR_H
#define MYSQL_VECTOR_H
template<class T>
class Vector {
public:
Vector(int sz = 10);
~Vector();
T& operator[](unsigned i);
const T& operator[](unsigned i) const;
unsigned size() const { return current_size; };
void push_back(const T &);
T& back();
void erase(unsigned index);
void clear();
void fill(unsigned new_size, T & obj);
Vector<T>& operator=(const Vector<T>&);
private:
T * items;
unsigned current_size;
unsigned increment_size;
unsigned alloced_size;
};
template<class T>
Vector<T>::Vector(int sz){
items = new T[sz];
current_size = 0;
alloced_size = sz;
increment_size = 50;
}
template<class T>
Vector<T>::~Vector(){
delete[] items;
/* safety for placement new usage */
items = 0;
current_size = 0;
alloced_size = 0;
}
template<class T>
T &
Vector<T>::operator[](unsigned i){
if(i >= current_size)
abort();
return items[i];
}
template<class T>
const T &
Vector<T>::operator[](unsigned i) const {
if(i >= current_size)
abort();
return items[i];
}
template<class T>
T &
Vector<T>::back(){
return (* this)[current_size - 1];
}
template<class T>
void
Vector<T>::push_back(const T & t){
if(current_size == alloced_size){
T * tmp = new T [alloced_size + increment_size];
if(!tmp)
abort();
for (unsigned k = 0; k < current_size; k++)
tmp[k] = items[k];
delete[] items;
items = tmp;
alloced_size = alloced_size + increment_size;
}
items[current_size] = t;
current_size++;
}
template<class T>
void
Vector<T>::erase(unsigned i){
if(i >= current_size)
abort();
for (unsigned k = i; k + 1 < current_size; k++)
items[k] = items[k + 1];
current_size--;
}
template<class T>
void
Vector<T>::clear(){
current_size = 0;
}
template<class T>
void
Vector<T>::fill(unsigned new_size, T & obj){
while(current_size <= new_size)
push_back(obj);
}
template<class T>
Vector<T>&
Vector<T>::operator=(const Vector<T>& obj){
if(this != &obj){
clear();
for(size_t i = 0; i<obj.size(); i++){
push_back(obj[i]);
}
}
return * this;
}
#endif
--- New file ---
+++ unittest/mysys/mf_tempfile-t.cc 07/03/26 11:53:00
/* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "ThreadRunner.h"
#include <errno.h>
#include <tap.h>
char tmpdir[FN_REFLEN]= {0};
/*
for (loop)
1. create temporary file
2. fill file with random number of bytes, first byte
written is set to the random value and then increased
by one for each written byte
3. read back filled data and verify length and content
*/
int test_create_temporary_file(ThreadContext* ctx)
{
char temp_file_path[FN_REFLEN];
char write_buf[256];
char read_buf[256];
File fd;
for (int loop= 0; loop < 1000; loop++)
{
/* Open temporary file */
if ((fd= create_temp_file(temp_file_path, tmpdir[0] ? tmpdir : NULL,
"tst",
O_RDWR | O_CREAT | O_SHARE | O_SHORT_LIVED | O_TEMPORARY,
MYF(MY_WME))) < 0)
return my_errno;
// fprintf(stderr, "temp_file_path: %s\n", temp_file_path);
for (unsigned i= 0; i < sizeof(write_buf); i++)
write_buf[i]= (char)((ctx->tid + loop + i) % 256);
/* Write bitpattern to the file */
if (my_write(fd, (byte*)write_buf, sizeof(write_buf),
MYF(MY_FNABP | MY_WME)))
{
my_close(fd, MYF(0));
return 1;
}
my_seek(fd, 0, MY_SEEK_SET, MYF(0));
/* Read bitpattern from the file */
if (my_read(fd, (byte*)read_buf, sizeof(read_buf),
MYF(MY_FNABP | MY_WME)))
{
my_close(fd, MYF(0));
return 1;
}
my_close(fd, MYF(0));
/* Check that the file does not exist */
if (!access(to, F_OK))
return 2;
if (memcmp(write_buf, read_buf, sizeof(read_buf)))
return 1;
}
return 0;
}
int main()
{
ThreadRunner runner;
const int num_threads= 10;
plan(2);
/*
Run with tmpdir set to NULL
*/
runner.add(test_create_temporary_file, num_threads);
runner.execute();
ok(runner.ok(), "Created temporary files, with %d threads", num_threads);
/*
Run the test a second time with tempdir set to current dir
allow EACCESS as a valid error
*/
my_getwd(tmpdir, sizeof(tmpdir), MYF(0));
runner.execute();
ok(runner.ok() || runner.error(EACCES),
"Created temporary files in %s, with %d threads", tmpdir, num_threads);
return exit_status();
}
| Thread |
|---|
| • bk commit into 5.1 tree (msvensson:1.2477) | msvensson | 26 Mar |