L4Re/departure

Annotated libfsserver/lib/pipes/pipe_paging.cc

544:754959243588
19 months ago Paul Boddie Sought to prevent a race condition when deleting pipe paging coordinators.
paul@93 1
/*
paul@93 2
 * A pipe paging coordinator, permitting memory sharing pipe endpoints.
paul@93 3
 *
paul@426 4
 * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
paul@93 5
 *
paul@93 6
 * This program is free software; you can redistribute it and/or
paul@93 7
 * modify it under the terms of the GNU General Public License as
paul@93 8
 * published by the Free Software Foundation; either version 2 of
paul@93 9
 * the License, or (at your option) any later version.
paul@93 10
 *
paul@93 11
 * This program is distributed in the hope that it will be useful,
paul@93 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@93 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@93 14
 * GNU General Public License for more details.
paul@93 15
 *
paul@93 16
 * You should have received a copy of the GNU General Public License
paul@93 17
 * along with this program; if not, write to the Free Software
paul@93 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@93 19
 * Boston, MA  02110-1301, USA
paul@93 20
 */
paul@93 21
paul@426 22
#include <algorithm>
paul@426 23
paul@94 24
#include <mem/memory_preallocated.h>
paul@94 25
paul@72 26
#include "page_queue_partitioned.h"
paul@65 27
#include "pipe_paging.h"
paul@65 28
paul@72 29
paul@72 30
paul@70 31
PipePaging::PipePaging(Memory *memory, offset_t size)
paul@426 32
: NotificationSupport(2), _memory(NULL)
paul@70 33
{
paul@426 34
    /* Employ a region size compatible with the configured page size. */
paul@426 35
paul@426 36
    _size = std::max<offset_t>(size, PAGE_SIZE);
paul@426 37
paul@72 38
    /* Reserve space for two pipe regions. */
paul@72 39
paul@89 40
    _memory = new MemoryPreallocated(memory, round(size, memory->region_size()) * 2);
paul@72 41
    _queue = new PageQueuePartitioned();
paul@72 42
    _pages = new Pages(_memory, _queue);
paul@72 43
paul@114 44
    /* Reset the mappers associated with the regions. */
paul@114 45
paul@72 46
    for (unsigned int i = 0; i < 2; i++)
paul@72 47
        _regions[i] = NULL;
paul@166 48
paul@166 49
    /* Initialise a region accessible by reader and writer. */
paul@166 50
paul@166 51
    _add_region();
paul@166 52
    _next_region();
paul@117 53
}
paul@117 54
paul@199 55
PipePaging::~PipePaging()
paul@118 56
{
paul@67 57
    /* Discard all regions from the pipe. */
paul@67 58
paul@72 59
    for (unsigned int i = 0; i < 2; i++)
paul@118 60
        discard_region(i);
paul@70 61
paul@124 62
    /* Release notifiers. */
paul@117 63
paul@133 64
    release_notifiers();
paul@117 65
paul@72 66
    /* Delete the page collection and related objects. */
paul@70 67
paul@70 68
    delete _pages;
paul@72 69
    delete _queue;
paul@72 70
    delete _memory;
paul@67 71
}
paul@67 72
paul@199 73
/* Return whether one or more endpoints have detached. */
paul@199 74
paul@199 75
int PipePaging::closed()
paul@199 76
{
paul@199 77
    return _active_endpoints < 2;
paul@199 78
}
paul@199 79
paul@199 80
/* Detach one endpoint, returning the number still active. */
paul@199 81
paul@199 82
unsigned int PipePaging::detach()
paul@199 83
{
paul@544 84
    std::lock_guard<std::mutex> guard(_lock);
paul@544 85
paul@199 86
    if (_active_endpoints)
paul@199 87
        _active_endpoints--;
paul@199 88
paul@199 89
    return _active_endpoints;
paul@199 90
}
paul@199 91
paul@199 92
/* Discard a region. */
paul@199 93
paul@199 94
void PipePaging::discard_region(unsigned int i)
paul@199 95
{
paul@199 96
    PageMapper *mapper = _regions[i];
paul@199 97
paul@199 98
    if (mapper != NULL)
paul@199 99
    {
paul@199 100
        _regions[i] = NULL;
paul@199 101
        delete mapper;
paul@199 102
    }
paul@199 103
}
paul@199 104
paul@65 105
/* Add a region to the sequence. */
paul@65 106
paul@166 107
PageMapper *PipePaging::_add_region()
paul@65 108
{
paul@72 109
    /* If the writer already accesses a different region to the reader, no new
paul@72 110
       region is added. */
paul@72 111
paul@72 112
    if (_writing != _reading)
paul@72 113
        return NULL;
paul@72 114
paul@72 115
    /* Select the other region of the pair being maintained. */
paul@72 116
paul@72 117
    _writing = 1 - _writing;
paul@72 118
paul@72 119
    /* Make a new mapper for the region. */
paul@72 120
paul@72 121
    PageMapper *mapper = new PageMapper(&_accessors[_writing], _pages);
paul@72 122
paul@72 123
    /* Initialise and record the mapper. */
paul@72 124
paul@72 125
    mapper->set_data_size(0);
paul@72 126
paul@72 127
    _regions[_writing] = mapper;
paul@117 128
paul@166 129
    /* Return the next region's mapper. */
paul@166 130
paul@166 131
    return mapper;
paul@166 132
}
paul@166 133
paul@166 134
PageMapper *PipePaging::add_region()
paul@166 135
{
paul@166 136
    PageMapper *mapper = _add_region();
paul@166 137
paul@117 138
    /* Let the writer notify the reader. */
paul@117 139
paul@484 140
    notify_others(PipePaging::WRITER, NOTIFY_CONTENT_AVAILABLE, NOTIFY_VALUES_NULL);
paul@117 141
paul@117 142
    /* Return the next region's mapper. */
paul@117 143
paul@72 144
    return mapper;
paul@65 145
}
paul@65 146
paul@72 147
/* Return the current region for reading. */
paul@65 148
paul@72 149
PageMapper *PipePaging::current_region()
paul@65 150
{
paul@72 151
    return _regions[_reading];
paul@65 152
}
paul@65 153
paul@166 154
/* Return the current region for reading or writing. */
paul@166 155
paul@166 156
PageMapper *PipePaging::current_region(bool writing)
paul@166 157
{
paul@166 158
    return _regions[writing ? _writing : _reading];
paul@166 159
}
paul@166 160
paul@72 161
/* Return the next region for the reader if the writer is using a different one.
paul@72 162
   Otherwise, return NULL. */
paul@65 163
paul@166 164
PageMapper *PipePaging::_next_region()
paul@65 165
{
paul@166 166
    /* If the reader already accesses the same region as the writer, no next
paul@72 167
       region can be obtained. */
paul@66 168
paul@72 169
    if (_reading == _writing)
paul@72 170
        return NULL;
paul@67 171
paul@72 172
    /* Detach and discard the current page mapper. */
paul@72 173
paul@118 174
    discard_region(_reading);
paul@65 175
paul@114 176
    /* Select the next region. */
paul@66 177
paul@72 178
    _reading = 1 - _reading;
paul@114 179
paul@114 180
    /* Return the next region's mapper. */
paul@114 181
paul@72 182
    return _regions[_reading];
paul@66 183
}
paul@66 184
paul@166 185
PageMapper *PipePaging::next_region()
paul@166 186
{
paul@166 187
    PageMapper *mapper = _next_region();
paul@166 188
paul@166 189
    /* Let the reader notify the writer. */
paul@166 190
paul@484 191
    notify_others(PipePaging::READER, NOTIFY_SPACE_AVAILABLE, NOTIFY_VALUES_NULL);
paul@166 192
paul@166 193
    return mapper;
paul@166 194
}
paul@166 195
paul@65 196
// vim: tabstop=4 expandtab shiftwidth=4