112027Sjungma@eit.uni-kl.de/*****************************************************************************
212027Sjungma@eit.uni-kl.de
312027Sjungma@eit.uni-kl.de  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412027Sjungma@eit.uni-kl.de  more contributor license agreements.  See the NOTICE file distributed
512027Sjungma@eit.uni-kl.de  with this work for additional information regarding copyright ownership.
612027Sjungma@eit.uni-kl.de  Accellera licenses this file to you under the Apache License, Version 2.0
712027Sjungma@eit.uni-kl.de  (the "License"); you may not use this file except in compliance with the
812027Sjungma@eit.uni-kl.de  License.  You may obtain a copy of the License at
912027Sjungma@eit.uni-kl.de
1012027Sjungma@eit.uni-kl.de    http://www.apache.org/licenses/LICENSE-2.0
1112027Sjungma@eit.uni-kl.de
1212027Sjungma@eit.uni-kl.de  Unless required by applicable law or agreed to in writing, software
1312027Sjungma@eit.uni-kl.de  distributed under the License is distributed on an "AS IS" BASIS,
1412027Sjungma@eit.uni-kl.de  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512027Sjungma@eit.uni-kl.de  implied.  See the License for the specific language governing
1612027Sjungma@eit.uni-kl.de  permissions and limitations under the License.
1712027Sjungma@eit.uni-kl.de
1812027Sjungma@eit.uni-kl.de *****************************************************************************/
1912027Sjungma@eit.uni-kl.de
2012027Sjungma@eit.uni-kl.de/*****************************************************************************
2112027Sjungma@eit.uni-kl.de
2212027Sjungma@eit.uni-kl.de  sc_mempool.cpp - Memory pools for small objects.
2312027Sjungma@eit.uni-kl.de
2412027Sjungma@eit.uni-kl.de  Original Author: Stan Y. Liao, Synopsys, Inc.
2512027Sjungma@eit.uni-kl.de
2612027Sjungma@eit.uni-kl.de  CHANGE LOG AT END OF FILE
2712027Sjungma@eit.uni-kl.de *****************************************************************************/
2812027Sjungma@eit.uni-kl.de
2912027Sjungma@eit.uni-kl.de
3012027Sjungma@eit.uni-kl.de
3112027Sjungma@eit.uni-kl.de
3212027Sjungma@eit.uni-kl.de//  <sc_mempool> is a class that manages the memory for small objects,
3312027Sjungma@eit.uni-kl.de//  of sizes <increment>, 2 * <increment>, ..., <num_pools> *
3412027Sjungma@eit.uni-kl.de//  <increment>.  When a memory request of <k> bytes is made through
3512027Sjungma@eit.uni-kl.de//  the memory pool, the smallest pool <j> such that <j> * <increment>
3612027Sjungma@eit.uni-kl.de//  >= <k> is used.  The default values of <increment> and <num_pools>
3712027Sjungma@eit.uni-kl.de//  are 8 and 8, respectively.  Each pool has an allocator, that
3812027Sjungma@eit.uni-kl.de//  simply keeps a free list of cells, and allocate new blocks
3912027Sjungma@eit.uni-kl.de//  whenever necessary.  We are relying on malloc() to return a
4012027Sjungma@eit.uni-kl.de//  properly aligned memory blocks.  Note that the memory blocks
4112027Sjungma@eit.uni-kl.de//  allocated by the mempool are never freed.  Thus, if purify is
4212027Sjungma@eit.uni-kl.de//  used, we may get MIU (memory-in-use) warnings.  To disable this,
4312027Sjungma@eit.uni-kl.de//  set the environment variable SYSTEMC_MEMPOOL_DONT_USE to 1.
4412027Sjungma@eit.uni-kl.de
4512027Sjungma@eit.uni-kl.de
4612027Sjungma@eit.uni-kl.destatic const char* dont_use_envstring = "SYSTEMC_MEMPOOL_DONT_USE";
4712027Sjungma@eit.uni-kl.destatic bool use_default_new = false;
4812027Sjungma@eit.uni-kl.de
4912027Sjungma@eit.uni-kl.de
5012027Sjungma@eit.uni-kl.de#include <stdio.h>
5112027Sjungma@eit.uni-kl.de#include <stdlib.h> // duplicate (c)stdlib.h headers for Solaris
5212027Sjungma@eit.uni-kl.de#include <cstdlib>
5312027Sjungma@eit.uni-kl.de#include "sysc/utils/sc_mempool.h"
5412027Sjungma@eit.uni-kl.de
5512027Sjungma@eit.uni-kl.denamespace sc_core {
5612027Sjungma@eit.uni-kl.de
5712027Sjungma@eit.uni-kl.de//  An allocator is one that handles a particular size.  It keeps a
5812027Sjungma@eit.uni-kl.de//  <free_list> from which a cell may be allocated quickly if there
5912027Sjungma@eit.uni-kl.de//  is one available.  If no cell is available from <free_list>, then
6012027Sjungma@eit.uni-kl.de//  the allocator tries to find whether space is available from the
6112027Sjungma@eit.uni-kl.de//  most-recently-allocated block, as pointed to by <next_avail>.  If
6212027Sjungma@eit.uni-kl.de//  so, then the cell pointed to by <next_avail> is returned, while
6312027Sjungma@eit.uni-kl.de//  <next_avail> is advanced.  If <next_avail> now points beyond
6412027Sjungma@eit.uni-kl.de//  the current block, then it's reset to 0.  On the other hand,
6512027Sjungma@eit.uni-kl.de//  if <next_avail> was 0 when a request to the block is made, then
6612027Sjungma@eit.uni-kl.de//  a new block is allocated by calling system malloc(), and the new
6712027Sjungma@eit.uni-kl.de//  block becomes the head of <block_list>.
6812027Sjungma@eit.uni-kl.de
6912027Sjungma@eit.uni-kl.de
7012027Sjungma@eit.uni-kl.declass sc_allocator {
7112027Sjungma@eit.uni-kl.de    friend class sc_mempool;
7212027Sjungma@eit.uni-kl.de
7312027Sjungma@eit.uni-kl.depublic:
7412027Sjungma@eit.uni-kl.de    sc_allocator( int blksz, int cellsz );
7512027Sjungma@eit.uni-kl.de    ~sc_allocator();
7612027Sjungma@eit.uni-kl.de    void* allocate();
7712027Sjungma@eit.uni-kl.de    void release(void* p);
7812027Sjungma@eit.uni-kl.de
7912027Sjungma@eit.uni-kl.de    void display_statistics();
8012027Sjungma@eit.uni-kl.de
8112027Sjungma@eit.uni-kl.deprivate:
8212027Sjungma@eit.uni-kl.de    union link {
8312027Sjungma@eit.uni-kl.de        link* next;
8412027Sjungma@eit.uni-kl.de        double align;          // alignment required.
8512027Sjungma@eit.uni-kl.de    };
8612027Sjungma@eit.uni-kl.de
8712027Sjungma@eit.uni-kl.de    int block_size;            // size of each block in bytes,
8812027Sjungma@eit.uni-kl.de                               // including the link
8912027Sjungma@eit.uni-kl.de    int cell_size;             // size of each cell in bytes
9012027Sjungma@eit.uni-kl.de
9112027Sjungma@eit.uni-kl.de    char* block_list;
9212027Sjungma@eit.uni-kl.de    link* free_list;
9312027Sjungma@eit.uni-kl.de    char* next_avail;
9412027Sjungma@eit.uni-kl.de
9512027Sjungma@eit.uni-kl.de    int total_alloc;
9612027Sjungma@eit.uni-kl.de    int total_freed;
9712027Sjungma@eit.uni-kl.de    int free_list_alloc;
9812027Sjungma@eit.uni-kl.de};
9912027Sjungma@eit.uni-kl.de
10012027Sjungma@eit.uni-kl.desc_allocator::sc_allocator( int blksz, int cellsz )
10112027Sjungma@eit.uni-kl.de  : block_size(sizeof(link) + (((blksz - 1) / cellsz) + 1) * cellsz),
10212027Sjungma@eit.uni-kl.de    cell_size(cellsz), block_list(0), free_list(0), next_avail(0),
10312027Sjungma@eit.uni-kl.de    total_alloc(0), total_freed(0), free_list_alloc(0)
10412027Sjungma@eit.uni-kl.de{}
10512027Sjungma@eit.uni-kl.de
10612027Sjungma@eit.uni-kl.desc_allocator::~sc_allocator()
10712027Sjungma@eit.uni-kl.de{
10812027Sjungma@eit.uni-kl.de    // Shouldn't free the block_list, since global objects that use
10912027Sjungma@eit.uni-kl.de    // the memory pool may not have been destroyed yet ...
11012027Sjungma@eit.uni-kl.de    // Let it leak, let it leak, let it leak ...
11112027Sjungma@eit.uni-kl.de}
11212027Sjungma@eit.uni-kl.de
11312027Sjungma@eit.uni-kl.devoid*
11412027Sjungma@eit.uni-kl.desc_allocator::allocate()
11512027Sjungma@eit.uni-kl.de{
11612027Sjungma@eit.uni-kl.de    void* result = 0;
11712027Sjungma@eit.uni-kl.de    total_alloc++;
11812027Sjungma@eit.uni-kl.de    if (free_list != 0) {
11912027Sjungma@eit.uni-kl.de        free_list_alloc++;
12012027Sjungma@eit.uni-kl.de        result = free_list;
12112027Sjungma@eit.uni-kl.de        free_list = free_list->next;
12212027Sjungma@eit.uni-kl.de        return result;
12312027Sjungma@eit.uni-kl.de    }
12412027Sjungma@eit.uni-kl.de    else if (next_avail != 0) {
12512027Sjungma@eit.uni-kl.de        result = next_avail;
12612027Sjungma@eit.uni-kl.de        next_avail += cell_size;
12712027Sjungma@eit.uni-kl.de        // next_avail goes beyond the block
12812027Sjungma@eit.uni-kl.de        if (next_avail >= block_list + block_size)
12912027Sjungma@eit.uni-kl.de            next_avail = 0;
13012027Sjungma@eit.uni-kl.de        return result;
13112027Sjungma@eit.uni-kl.de    }
13212027Sjungma@eit.uni-kl.de    else {  // (next_avail == 0)
13312027Sjungma@eit.uni-kl.de        link* new_block = (link*) malloc(block_size);  // need alignment?
13412027Sjungma@eit.uni-kl.de        new_block->next = (link*) block_list;
13512027Sjungma@eit.uni-kl.de        block_list = (char*) new_block;
13612027Sjungma@eit.uni-kl.de        result = (block_list + sizeof(link));
13712027Sjungma@eit.uni-kl.de        // Assume that the block will hold more than one cell ... why
13812027Sjungma@eit.uni-kl.de        // wouldn't it?
13912027Sjungma@eit.uni-kl.de        next_avail = ((char*) result) + cell_size;
14012027Sjungma@eit.uni-kl.de        return result;
14112027Sjungma@eit.uni-kl.de    }
14212027Sjungma@eit.uni-kl.de}
14312027Sjungma@eit.uni-kl.de
14412027Sjungma@eit.uni-kl.devoid
14512027Sjungma@eit.uni-kl.desc_allocator::release(void* p)
14612027Sjungma@eit.uni-kl.de{
14712027Sjungma@eit.uni-kl.de    total_freed++;
14812027Sjungma@eit.uni-kl.de    ((link*) p)->next = free_list;
14912027Sjungma@eit.uni-kl.de    free_list = (link*) p;
15012027Sjungma@eit.uni-kl.de}
15112027Sjungma@eit.uni-kl.de
15212027Sjungma@eit.uni-kl.devoid
15312027Sjungma@eit.uni-kl.desc_allocator::display_statistics()
15412027Sjungma@eit.uni-kl.de{
15512027Sjungma@eit.uni-kl.de    int nblocks = 0;
15612027Sjungma@eit.uni-kl.de    for (link* b = (link*) block_list; b != 0; b = b->next)
15712027Sjungma@eit.uni-kl.de        nblocks++;
15812027Sjungma@eit.uni-kl.de    printf("size %3d: %2d block(s), %3d requests (%3d from free list), %3d freed.\n",
15912027Sjungma@eit.uni-kl.de           cell_size, nblocks, total_alloc, free_list_alloc, total_freed);
16012027Sjungma@eit.uni-kl.de}
16112027Sjungma@eit.uni-kl.de
16212027Sjungma@eit.uni-kl.de
16312027Sjungma@eit.uni-kl.destatic const int cell_sizes[] = {
16412027Sjungma@eit.uni-kl.de/* 0 */   0,
16512027Sjungma@eit.uni-kl.de/* 1 */   8,
16612027Sjungma@eit.uni-kl.de/* 2 */  16,
16712027Sjungma@eit.uni-kl.de/* 3 */  24,
16812027Sjungma@eit.uni-kl.de/* 4 */  32,
16912027Sjungma@eit.uni-kl.de/* 5 */  48,
17012027Sjungma@eit.uni-kl.de/* 6 */  64,
17112027Sjungma@eit.uni-kl.de/* 7 */  80,
17212027Sjungma@eit.uni-kl.de/* 8 */  96,
17312027Sjungma@eit.uni-kl.de/* 9 */ 128
17412027Sjungma@eit.uni-kl.de};
17512027Sjungma@eit.uni-kl.de
17612027Sjungma@eit.uni-kl.destatic const int cell_size_to_allocator[] = {
17712027Sjungma@eit.uni-kl.de/*  0 */    0,
17812027Sjungma@eit.uni-kl.de/*  1 */    1,
17912027Sjungma@eit.uni-kl.de/*  2 */    2,
18012027Sjungma@eit.uni-kl.de/*  3 */    3,
18112027Sjungma@eit.uni-kl.de/*  4 */    4,
18212027Sjungma@eit.uni-kl.de/*  5 */    5,
18312027Sjungma@eit.uni-kl.de/*  6 */    5,
18412027Sjungma@eit.uni-kl.de/*  7 */    6,
18512027Sjungma@eit.uni-kl.de/*  8 */    6,
18612027Sjungma@eit.uni-kl.de/*  9 */    7,
18712027Sjungma@eit.uni-kl.de/* 10 */    7,
18812027Sjungma@eit.uni-kl.de/* 11 */    8,
18912027Sjungma@eit.uni-kl.de/* 12 */    8,
19012027Sjungma@eit.uni-kl.de/* 13 */    9,
19112027Sjungma@eit.uni-kl.de/* 14 */    9,
19212027Sjungma@eit.uni-kl.de/* 15 */    9,
19312027Sjungma@eit.uni-kl.de/* 16 */    9
19412027Sjungma@eit.uni-kl.de};
19512027Sjungma@eit.uni-kl.de
19612027Sjungma@eit.uni-kl.de
19712027Sjungma@eit.uni-kl.declass sc_mempool_int {
19812027Sjungma@eit.uni-kl.de    friend class sc_mempool;
19912027Sjungma@eit.uni-kl.de
20012027Sjungma@eit.uni-kl.depublic:
20112027Sjungma@eit.uni-kl.de    sc_mempool_int(int blksz, int npools, int incr);
20212027Sjungma@eit.uni-kl.de    ~sc_mempool_int();
20312027Sjungma@eit.uni-kl.de    void* do_allocate(std::size_t);
20412027Sjungma@eit.uni-kl.de    void  do_release(void*, std::size_t);
20512027Sjungma@eit.uni-kl.de
20612027Sjungma@eit.uni-kl.de    void display_statistics();
20712027Sjungma@eit.uni-kl.de
20812027Sjungma@eit.uni-kl.deprivate:
20912027Sjungma@eit.uni-kl.de    sc_allocator** allocators;
21012027Sjungma@eit.uni-kl.de    int num_pools;
21112027Sjungma@eit.uni-kl.de    int increment;
21212027Sjungma@eit.uni-kl.de    int max_size;
21312027Sjungma@eit.uni-kl.de};
21412027Sjungma@eit.uni-kl.de
21512027Sjungma@eit.uni-kl.de
21612027Sjungma@eit.uni-kl.destatic bool
21712027Sjungma@eit.uni-kl.decompute_use_default_new()
21812027Sjungma@eit.uni-kl.de{
21912027Sjungma@eit.uni-kl.de    const char* e = getenv(dont_use_envstring);
22012027Sjungma@eit.uni-kl.de    return (e != 0) && (atoi(e) != 0);
22112027Sjungma@eit.uni-kl.de}
22212027Sjungma@eit.uni-kl.de
22312027Sjungma@eit.uni-kl.desc_mempool_int::sc_mempool_int(int blksz, int npools, int incr) :
22412027Sjungma@eit.uni-kl.de    allocators(0), num_pools(0), increment(0), max_size(0)
22512027Sjungma@eit.uni-kl.de{
22612027Sjungma@eit.uni-kl.de    use_default_new = compute_use_default_new();
22712027Sjungma@eit.uni-kl.de    if (! use_default_new) {
22812027Sjungma@eit.uni-kl.de        num_pools = npools;
22912027Sjungma@eit.uni-kl.de        increment = incr;
23012027Sjungma@eit.uni-kl.de        max_size = cell_sizes[sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1];
23112027Sjungma@eit.uni-kl.de        allocators = new sc_allocator*[npools + 1];
23212027Sjungma@eit.uni-kl.de        for (int i = 1; i <= npools; ++i)
23312027Sjungma@eit.uni-kl.de            allocators[i] = new sc_allocator(blksz, cell_sizes[i]);
23412027Sjungma@eit.uni-kl.de        allocators[0] = allocators[1];
23512027Sjungma@eit.uni-kl.de    }
23612027Sjungma@eit.uni-kl.de}
23712027Sjungma@eit.uni-kl.de
23812027Sjungma@eit.uni-kl.desc_mempool_int::~sc_mempool_int()
23912027Sjungma@eit.uni-kl.de{
24012027Sjungma@eit.uni-kl.de    for (int i = 1; i <= num_pools; ++i)
24112027Sjungma@eit.uni-kl.de        delete allocators[i];
24212027Sjungma@eit.uni-kl.de    delete[] allocators;
24312027Sjungma@eit.uni-kl.de}
24412027Sjungma@eit.uni-kl.de
24512027Sjungma@eit.uni-kl.destatic sc_mempool_int* the_mempool = 0;
24612027Sjungma@eit.uni-kl.de
24712027Sjungma@eit.uni-kl.devoid*
24812027Sjungma@eit.uni-kl.desc_mempool_int::do_allocate(std::size_t sz)
24912027Sjungma@eit.uni-kl.de{
25012027Sjungma@eit.uni-kl.de    int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1];
25112027Sjungma@eit.uni-kl.de    void* p = allocators[which_allocator]->allocate();
25212027Sjungma@eit.uni-kl.de    return p;
25312027Sjungma@eit.uni-kl.de}
25412027Sjungma@eit.uni-kl.de
25512027Sjungma@eit.uni-kl.devoid
25612027Sjungma@eit.uni-kl.desc_mempool_int::do_release(void* p, std::size_t sz)
25712027Sjungma@eit.uni-kl.de{
25812027Sjungma@eit.uni-kl.de    int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1];
25912027Sjungma@eit.uni-kl.de    allocators[which_allocator]->release(p);
26012027Sjungma@eit.uni-kl.de}
26112027Sjungma@eit.uni-kl.de
26212027Sjungma@eit.uni-kl.devoid
26312027Sjungma@eit.uni-kl.desc_mempool_int::display_statistics()
26412027Sjungma@eit.uni-kl.de{
26512027Sjungma@eit.uni-kl.de    printf("*** Memory Pool Statistics ***\n");
26612027Sjungma@eit.uni-kl.de    for (int i = 1; i <= num_pools; ++i)
26712027Sjungma@eit.uni-kl.de        allocators[i]->display_statistics();
26812027Sjungma@eit.uni-kl.de}
26912027Sjungma@eit.uni-kl.de
27012027Sjungma@eit.uni-kl.de/****************************************************************************/
27112027Sjungma@eit.uni-kl.de
27212027Sjungma@eit.uni-kl.devoid*
27312027Sjungma@eit.uni-kl.desc_mempool::allocate(std::size_t sz)
27412027Sjungma@eit.uni-kl.de{
27512027Sjungma@eit.uni-kl.de    if (use_default_new)
27612027Sjungma@eit.uni-kl.de        return ::operator new(sz);
27712027Sjungma@eit.uni-kl.de
27812027Sjungma@eit.uni-kl.de    if (the_mempool == 0) {
27912027Sjungma@eit.uni-kl.de        use_default_new = compute_use_default_new();
28012027Sjungma@eit.uni-kl.de        if (use_default_new)
28112027Sjungma@eit.uni-kl.de            return ::operator new(sz);
28212027Sjungma@eit.uni-kl.de
28312027Sjungma@eit.uni-kl.de        // Note that the_mempool is never freed.  This is going to cause
28412027Sjungma@eit.uni-kl.de        // memory leaks when the program exits.
28512027Sjungma@eit.uni-kl.de        the_mempool = new sc_mempool_int( 1984, sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1, 8 );
28612027Sjungma@eit.uni-kl.de    }
28712027Sjungma@eit.uni-kl.de
28812027Sjungma@eit.uni-kl.de    if (sz > (unsigned) the_mempool->max_size)
28912027Sjungma@eit.uni-kl.de        return ::operator new(sz);
29012027Sjungma@eit.uni-kl.de
29112027Sjungma@eit.uni-kl.de    return the_mempool->do_allocate(sz);
29212027Sjungma@eit.uni-kl.de}
29312027Sjungma@eit.uni-kl.de
29412027Sjungma@eit.uni-kl.devoid
29512027Sjungma@eit.uni-kl.desc_mempool::release(void* p, std::size_t sz)
29612027Sjungma@eit.uni-kl.de{
29712027Sjungma@eit.uni-kl.de    if (p) {
29812027Sjungma@eit.uni-kl.de
29912027Sjungma@eit.uni-kl.de        if (use_default_new || sz > (unsigned) the_mempool->max_size) {
30012027Sjungma@eit.uni-kl.de            ::operator delete(p);
30112027Sjungma@eit.uni-kl.de            return;
30212027Sjungma@eit.uni-kl.de        }
30312027Sjungma@eit.uni-kl.de
30412027Sjungma@eit.uni-kl.de        the_mempool->do_release(p, sz);
30512027Sjungma@eit.uni-kl.de    }
30612027Sjungma@eit.uni-kl.de}
30712027Sjungma@eit.uni-kl.de
30812027Sjungma@eit.uni-kl.devoid
30912027Sjungma@eit.uni-kl.desc_mempool::display_statistics()
31012027Sjungma@eit.uni-kl.de{
31112027Sjungma@eit.uni-kl.de    if (the_mempool && !use_default_new) {
31212027Sjungma@eit.uni-kl.de        the_mempool->display_statistics();
31312027Sjungma@eit.uni-kl.de    } else {
31412027Sjungma@eit.uni-kl.de        printf("SystemC info: no memory allocation was done through the memory pool.\n");
31512027Sjungma@eit.uni-kl.de    }
31612027Sjungma@eit.uni-kl.de}
31712027Sjungma@eit.uni-kl.de
31812027Sjungma@eit.uni-kl.de} // namespace sc_core
31912027Sjungma@eit.uni-kl.de
32012027Sjungma@eit.uni-kl.de// $Log: sc_mempool.cpp,v $
32112027Sjungma@eit.uni-kl.de// Revision 1.4  2011/08/26 20:46:18  acg
32212027Sjungma@eit.uni-kl.de//  Andy Goodrich: moved the modification log to the end of the file to
32312027Sjungma@eit.uni-kl.de//  eliminate source line number skew when check-ins are done.
32412027Sjungma@eit.uni-kl.de//
32512027Sjungma@eit.uni-kl.de// Revision 1.3  2011/08/24 22:05:56  acg
32612027Sjungma@eit.uni-kl.de//  Torsten Maehne: initialization changes to remove warnings.
32712027Sjungma@eit.uni-kl.de//
32812027Sjungma@eit.uni-kl.de// Revision 1.2  2011/02/18 20:38:44  acg
32912027Sjungma@eit.uni-kl.de//  Andy Goodrich: Updated Copyright notice.
33012027Sjungma@eit.uni-kl.de//
33112027Sjungma@eit.uni-kl.de// Revision 1.1.1.1  2006/12/15 20:20:06  acg
33212027Sjungma@eit.uni-kl.de// SystemC 2.3
33312027Sjungma@eit.uni-kl.de//
33412027Sjungma@eit.uni-kl.de// Revision 1.3  2006/01/13 18:53:10  acg
33512027Sjungma@eit.uni-kl.de// Andy Goodrich: Added $Log command so that CVS comments are reproduced in
33612027Sjungma@eit.uni-kl.de// the source.
33712027Sjungma@eit.uni-kl.de
33812027Sjungma@eit.uni-kl.de// taf
339