In article <news:c8ettt$grf$1@tomahawk.unsw.edu.au>
mikegw <mikegw20@hotmail.spammers.must.die.com> writes:[color=blue]
>I am currently using an implementation of sysV shared memory.[/color]
The underlying shared-memory implementation is off-topic, but
this is an issue in a "general C" sense, in one important way:
[color=blue]
>The entire shared memory is allocated is one continuous block
>of which I get the pointer to the head, everything should be done
>as offsets from this.[/color]
There is a way to restate this without pulling in shared-memory
issues, and it goes like this:
"I have a large block of special, but otherwise undifferentiated,
C-bytes, and I need to write a general-purpose allocator, much
like malloc(), that works within this block."
Unfortunately, the Standard C answer is "you cannot write a malloc()".
The malloc() function returns memory that is "suitably aligned"
for any data type, and Standard C does not give you -- where "you"
means "anyone other than the implementor writing malloc() in the
first place" -- the tools needed to discover this alignment.
In your case, though, you have a fighting chance, because you do
not have to write a fully-general malloc(). Instead, you can
simply collect up all the types you actually use, inside these
data structures in this special block of memory, and write an
allocator that only aligns suitably for these types.
(Or you can even just sleaze out entirely and assume that sizeof(double)
is the maximum required alignment, that the block is already aligned
for use as "double", and that your two structures, since they both
contain "double", are also so aligned. :-) )
[color=blue]
>At the moment I have two data structures, a head to a linked list
>which in it contains the pointer to the first element in the linked
>list (this is redundant as far as I can work out) and the list
>itself.[/color]
The data structures you show here are not linked-lists.
[color=blue]
>The data structures are as follows
>
>struct ipc_particle
>{
> int zone_id;
> int zone[3];
> int fur_flag;
> double radiusR; //radius of repulsion (contact radius)
> double radiusA; //radius of attraction (influence radius)
> double mass; //mass
> double poissons; //poissons ratio
> double youngs; //Young's modulus
> double zeta; //zeta potential
> double force[3]; //force
> double position[3]; //position psn[0]=x, psn[1]=y, psn[2]=z
> double velocity[3]; //velocity
>
>};[/color]
In particular, an "ipc_particle" structure does not contain a
pointer to another "ipc_particle", so it cannot be a list. That
leaves:
[color=blue]
>struct dem_mem
>{
> int particles;
> int processors;
> int run;
> int time_semaphore;
> double clock;
> struct ipc_particle* particle_head;
> };[/color]
and here a "struct dem_mem" does not contain a pointer to another
"dem_mem", so it cannot be a list either.
[color=blue]
>to calculate the dem_mem->particle_head I currently use particle_head =
>dem_mem_pointer+(sizeof(struct dem_mem))[/color]
If "dem_mem_pointer" has type "char *", this is likely to work.
If "dem_mem_pointer" has type "struct dem_mem *", this is still
likely to work, but wastes enormous amounts of space -- you just
want to add 1, not something like 32 or so. You want to "move
forward" in your block-of-bytes by 1 "struct dem_mem" object, and
pointer arithmetic works in units of the pointed-to objects.
[color=blue]
>to reference the elements in the linked list I just use
>particle_head[offset].zone_id for example.[/color]
This is not a linked-list access, but rather an array access:
a "struct dem_mem"'s particle_head points to the first element
of an array (of unspecified size) of "struct ipc_particle"s,
and you move forward in memory by "offset" units of that size:
+-----------------+
| particles |
| processors |
: ... :
| particle_head --|---------\
+-----------------+ |
|
|
/-----------------------------/
|
_\|+-----------------------...
| zone_id | zone_id |
| zone | zone |
| fur_flag | fur_flag |
: : :
| velocity | velocity |
+-----------------------...
Given that "particle_head" points to the first element (subscript
0) of the array, particle_head[0] names that entire array element
-- the whole structure, with fields like "zone_id". particle_head[1]
names the entire array element "one further along" in memory,
particle_head[2] names the entire element "two further along", and
so forth.
This is the very same pointer arithmetic, stepping along by units
of the thing pointed-to, that you get if you add 1 to a "struct
dem_mem". The only difference is that the size of the target of
a "dem_mem" pointer has no defined relationship to the size of the
target of an "ipc_particle" pointer. The distance (measured in
bytes) that "+ 1" moves, changes!
[color=blue]
>I don't like how I calculate the particle_head, for a start I get a warning
>about adding an int to a pointer.[/color]
Adding an int to a pointer is fine -- this is how subscripting
works in C. The problem lies elsewhere.
[color=blue]
>Basically I know that my first element is sizeof(struct dem_mem) away from
>the header pointer. Is there a better way to get this?[/color]
If you have a C99 compiler, you can replace the entire technique
with a "flexible array member", where "struct dem_mem" ends with
an unspecified number of "struct ipc_particle"s:
struct ipc_particle { ... as before ... };
struct dem_mem {
... as before, but ending with ...
struct ipc_particle particles[];
};
Now the only thing you need to your malloc()-like allocator to
handle is the "struct dem_mem" itself. See the comp.lang.c FAQ
for details on C99 flexible array members, and ways to fake them
in C89. (Given that you already depend on shared-memory, depending
on things not officially valid in C89, such as faked flexible array
members, is probably not going to cause additional portabiility
problems.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.