diff --git a/sortix/include/sortix/kernel/yielder.h b/sortix/include/sortix/kernel/yielder.h
new file mode 100644
index 00000000..23590180
--- /dev/null
+++ b/sortix/include/sortix/kernel/yielder.h
@@ -0,0 +1,70 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2013.
+
+ This file is part of Sortix.
+
+ Sortix 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, either version 3 of the License, or (at your option) any later
+ version.
+
+ Sortix 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
+ Sortix. If not, see .
+
+ sortix/kernel/yielder.h
+ Template that allows creation of easily-iterable sequences.
+
+*******************************************************************************/
+
+#ifndef INCLUDE_SORTIX_KERNEL_YIELDER_H
+#define INCLUDE_SORTIX_KERNEL_YIELDER_H
+
+namespace Sortix {
+
+class finished_yielder { };
+
+template class yielder_iterator
+{
+public:
+ yielder_iterator(yielder_type yielder) : yielder_object(yielder)
+ {
+ has_value = yielder_object.yield(¤t_value);
+ }
+
+ bool is_finished() const
+ {
+ return !has_value;
+ }
+
+ bool operator!=(const yielder_iterator& other) const
+ {
+ return !(is_finished() && other.is_finished());
+ }
+
+ yielded_type operator*()
+ {
+ return current_value;
+ }
+
+ const yielder_iterator& operator++()
+ {
+ has_value = yielder_object.yield(¤t_value);
+ return *this;
+ }
+
+private:
+ yielder_type yielder_object;
+ yielded_type current_value;
+ bool has_value;
+
+};
+
+} // namespace Sortix
+
+#endif
diff --git a/sortix/include/sortix/mman.h b/sortix/include/sortix/mman.h
index 2cb20eae..28b36a74 100644
--- a/sortix/include/sortix/mman.h
+++ b/sortix/include/sortix/mman.h
@@ -48,4 +48,9 @@
#define MAP_SHARED (1<<0)
#define MAP_PRIVATE (1<<1)
+#define MAP_ANONYMOUS (1<<2)
+#define MAP_FIXED (1<<3)
+
+#define MAP_FAILED ((void*) -1)
+
#endif
diff --git a/sortix/segment.cpp b/sortix/segment.cpp
index 2b91b218..67c6a42e 100644
--- a/sortix/segment.cpp
+++ b/sortix/segment.cpp
@@ -24,14 +24,19 @@
#include
+#include
#include
#include
#include
+#include
+
#include
+#include
#include
#include
#include
+#include
namespace Sortix {
@@ -105,4 +110,141 @@ bool AddSegment(Process* process, const struct segment* new_segment)
return true;
}
+class segment_gaps
+{
+ typedef yielder_iterator my_iterator;
+
+public:
+ segment_gaps(finished_yielder) : process(0) { }
+
+ segment_gaps(Process* process) :
+ process(process),
+ current_segment_index(0),
+ checked_leading(false),
+ checked_trailing(false)
+ {
+ Memory::GetUserVirtualArea(&userspace_addr, &userspace_size);
+ }
+
+ bool yield(struct segment* result)
+ {
+ // process->segment_lock is held at this point.
+
+ // Check if we have finished iterating all the segments.
+ if ( !process )
+ return false;
+
+ // If the process has no segments at all, our job is really easy.
+ if ( !process->segments_used )
+ {
+ result->addr = userspace_addr;
+ result->size = userspace_size;
+ result->prot = 0;
+ process = NULL;
+ return true;
+ }
+
+ // Find out whether there is a gap before the first segment.
+ if ( !checked_leading && (checked_leading = true) &&
+ process->segments[0].addr != userspace_addr )
+ {
+ result->addr = userspace_addr;
+ result->size = process->segments[0].addr - userspace_addr;
+ result->prot = 0;
+ return true;
+ }
+
+ // Search through the segments until a gap follows one.
+ while ( current_segment_index + 1 < process->segments_used )
+ {
+ result->addr = process->segments[current_segment_index].addr +
+ process->segments[current_segment_index].size;
+ result->size = process->segments[current_segment_index+1].addr -
+ result->addr;
+ result->prot = 0;
+ current_segment_index++;
+ if ( result->size )
+ return true;
+ }
+
+ // Find out if there is a gap after the last segment.
+ if ( !checked_trailing && (checked_trailing = true) &&
+ process->segments[process->segments_used-1].addr +
+ process->segments[process->segments_used-1].size !=
+ userspace_addr + userspace_size )
+ {
+ result->addr = process->segments[process->segments_used-1].addr +
+ process->segments[process->segments_used-1].size;
+ result->size = userspace_addr + userspace_size - result->addr;
+ result->prot = 0;
+ return true;
+ }
+
+ process = NULL;
+
+ return false;
+ }
+
+ my_iterator begin() const
+ {
+ return my_iterator(segment_gaps(*this));
+ }
+
+ my_iterator end() const
+ {
+ return my_iterator(segment_gaps{finished_yielder{}});
+ }
+
+private:
+ Process* process;
+ uintptr_t userspace_addr;
+ size_t userspace_size;
+ size_t current_segment_index;
+ bool checked_leading;
+ bool checked_trailing;
+
+};
+
+bool PlaceSegment(struct segment* solution, Process* process, void* addr_ptr,
+ size_t size, int flags)
+{
+ // process->segment_lock is held at this point.
+
+ assert(!(flags & MAP_FIXED));
+
+ uintptr_t addr = (uintptr_t) addr_ptr;
+ bool found_any = false;
+ size_t best_distance = 0;
+ struct segment best;
+
+ for ( struct segment gap : segment_gaps(process) )
+ {
+ if ( gap.size < size )
+ continue;
+ if ( gap.addr <= addr && addr + size - gap.addr <= gap.size )
+ {
+ solution->addr = addr;
+ solution->size = size;
+ solution->prot = 0;
+ return true;
+ }
+ struct segment attempt;
+ size_t distance;
+ attempt.addr = gap.addr;
+ attempt.size = size;
+ attempt.prot = 0;
+ distance = addr < attempt.addr ? attempt.addr - addr : addr - attempt.addr;
+ if ( !found_any|| distance < best_distance )
+ found_any = true, best_distance = distance, best = attempt;
+ attempt.addr = gap.addr + gap.size - size;
+ attempt.size = size;
+ attempt.prot = 0;
+ distance = addr < attempt.addr ? attempt.addr - addr : addr - attempt.addr;
+ if ( !found_any|| distance < best_distance )
+ found_any = true, best_distance = distance, best = attempt;
+ }
+
+ return *solution = best, found_any;
+}
+
} // namespace Sortix