| #include <memory> |
| #include <vector> |
| |
| #include <cstdio> |
| |
| #include "cppunit/cppunit_proxy.h" |
| |
| #if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES) |
| using namespace std; |
| #endif |
| |
| // |
| // TestCase class |
| // |
| class AllocatorTest : public CPPUNIT_NS::TestCase |
| { |
| CPPUNIT_TEST_SUITE(AllocatorTest); |
| CPPUNIT_TEST(zero_allocation); |
| #if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS) |
| CPPUNIT_TEST(bad_alloc_test); |
| #endif |
| #if defined (STLPORT) && defined (_STLP_THREADS) && defined (_STLP_USE_PERTHREAD_ALLOC) |
| CPPUNIT_TEST(per_thread_alloc); |
| #endif |
| CPPUNIT_TEST_SUITE_END(); |
| |
| protected: |
| void zero_allocation(); |
| void bad_alloc_test(); |
| void per_thread_alloc(); |
| }; |
| |
| CPPUNIT_TEST_SUITE_REGISTRATION(AllocatorTest); |
| |
| // |
| // tests implementation |
| // |
| void AllocatorTest::zero_allocation() |
| { |
| typedef allocator<char> CharAllocator; |
| CharAllocator charAllocator; |
| |
| char* buf = charAllocator.allocate(0); |
| charAllocator.deallocate(buf, 0); |
| |
| charAllocator.deallocate(0, 0); |
| } |
| |
| #if !defined (STLPORT) || defined (_STLP_USE_EXCEPTIONS) |
| |
| struct BigStruct |
| { |
| char _data[4096]; |
| }; |
| |
| void AllocatorTest::bad_alloc_test() |
| { |
| typedef allocator<BigStruct> BigStructAllocType; |
| BigStructAllocType bigStructAlloc; |
| |
| try { |
| //Lets try to allocate almost 4096 Go (on most of the platforms) of memory: |
| BigStructAllocType::pointer pbigStruct = bigStructAlloc.allocate(1024 * 1024 * 1024); |
| |
| //Allocation failed but no exception thrown |
| CPPUNIT_ASSERT( pbigStruct != 0 ); |
| |
| // Just it case it succeeds: |
| bigStructAlloc.deallocate(pbigStruct, 1024 * 1024 * 1024); |
| } |
| catch (bad_alloc const&) { |
| } |
| catch (...) { |
| //We shouldn't be there: |
| //Not bad_alloc exception thrown. |
| CPPUNIT_FAIL; |
| } |
| } |
| #endif |
| |
| #if defined (STLPORT) && defined (_STLP_THREADS) && defined (_STLP_USE_PERTHREAD_ALLOC) |
| # include <pthread.h> |
| |
| class SharedDatas |
| { |
| public: |
| typedef vector<int, per_thread_allocator<int> > thread_vector; |
| |
| SharedDatas(size_t nbElems) : threadVectors(nbElems, (thread_vector*)0) { |
| pthread_mutex_init(&mutex, 0); |
| pthread_cond_init(&condition, 0); |
| } |
| |
| ~SharedDatas() { |
| for (size_t i = 0; i < threadVectors.size(); ++i) { |
| delete threadVectors[i]; |
| } |
| } |
| |
| size_t initThreadVector() { |
| size_t ret; |
| |
| pthread_mutex_lock(&mutex); |
| |
| for (size_t i = 0; i < threadVectors.size(); ++i) { |
| if (threadVectors[i] == 0) { |
| threadVectors[i] = new thread_vector(); |
| ret = i; |
| break; |
| } |
| } |
| |
| if (ret != threadVectors.size() - 1) { |
| //We wait for other thread(s) to call this method too: |
| printf("Thread %d wait\n", ret); |
| pthread_cond_wait(&condition, &mutex); |
| } |
| else { |
| //We are the last thread calling this method, we signal this |
| //to the other thread(s) that might be waiting: |
| printf("Thread %d signal\n", ret); |
| pthread_cond_signal(&condition); |
| } |
| |
| pthread_mutex_unlock(&mutex); |
| |
| return ret; |
| } |
| |
| thread_vector& getThreadVector(size_t index) { |
| //We return other thread thread_vector instance: |
| return *threadVectors[(index + 1 == threadVectors.size()) ? 0 : index + 1]; |
| } |
| |
| private: |
| pthread_mutex_t mutex; |
| pthread_cond_t condition; |
| vector<thread_vector*> threadVectors; |
| }; |
| |
| void* f(void* pdatas) { |
| SharedDatas *psharedDatas = (SharedDatas*)pdatas; |
| |
| int threadIndex = psharedDatas->initThreadVector(); |
| |
| for (int i = 0; i < 100; ++i) { |
| psharedDatas->getThreadVector(threadIndex).push_back(i); |
| } |
| |
| return 0; |
| } |
| |
| void AllocatorTest::per_thread_alloc() |
| { |
| const size_t nth = 2; |
| SharedDatas datas(nth); |
| pthread_t t[nth]; |
| |
| size_t i; |
| for (i = 0; i < nth; ++i) { |
| pthread_create(&t[i], 0, f, &datas); |
| } |
| |
| for (i = 0; i < nth; ++i ) { |
| pthread_join(t[i], 0); |
| } |
| } |
| #endif |