473,326 Members | 2,126 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,326 software developers and data experts.

Reentrant code

I am modifying some legacy code, to make the functions reentrant. I use
lots of global data (large nested structs) to pass data around quicky.
The global structures are far too large (in size) for each of my
functions to maintain copies.

Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.
Jun 27 '08 #1
12 3433
On Jun 17, 12:10 pm, Bit Byte <r...@yourbox.comwrote:
I am modifying some legacy code, to make the functions reentrant. I use
lots of global data (large nested structs) to pass data around quicky.
The global structures are far too large (in size) for each of my
functions to maintain copies.

Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.

Your question is off-topic as C does not say anything about multi-
threading.

<off-topic>
That greatly depends on the function you are trying to make re-
entrant. A general approach is to use some sort of mutex to prevent
the global data from being altered in two place in the same places
leaving the result in an inconsistent state.
<just-curious>
You say your code uses a lot of globals. I think that's a bad idea
and may be you should do a design review.
</just-curious>
One thing to mention here is mutex uses co-operative locking. To
elaborate, mutex is a door through which only one person can enter at
a time and threads are standing in a queue. If the threads are
maintaining the queue, everything is great but the door does not stop
you from jumping out of the window.

Its not the running code that is to be made re-entrant. The access to
the shared data is to be synchronized. Lock the mutex before
modification and unlock it when you are done. Depending on your
problem, you may even have to use condition variables.
</off-topic>
Jun 27 '08 #2
On Jun 17, 11:33 am, rahul <rahulsin...@gmail.comwrote:
On Jun 17, 12:10 pm, Bit Byte <r...@yourbox.comwrote:
I am modifying some legacy code, to make the functions reentrant. I use
lots of global data (large nested structs) to pass data around quicky.
The global structures are far too large (in size) for each of my
functions to maintain copies.
Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.

Your question is off-topic as C does not say anything about multi-
threading.
Re-entrancy doesn't have to do anything with threads or thread safety,
but indeed ISO C doesn't mention thing such as 'reentrancy', 'threads'
etc.
"Bit Byte", if you are programming for windows, try a windows
newsgroup. If you are programming for unix, try comp.unix.programmer.
<snip rahul's off-topic reply>
Jun 27 '08 #3
vi******@gmail.com writes:
[...]
Re-entrancy doesn't have to do anything with threads or thread safety,
but indeed ISO C doesn't mention thing such as 'reentrancy', 'threads'
etc.
[...]

It does, but only briefly.

C99 7.1.4p4:

The functions in the standard library are not guaranteed to be
reentrant and may modify objects with static storage duration.

footnote:

Thus, a signal handler cannot, in general, call standard library
functions.

There's also an index entry for "reentrancy", pointing to 5.1.2.3
(Program execution) and 5.2.3 (Signals an interrupts) as well as
7.1.4.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #4
Bit Byte wrote:
I am modifying some legacy code, to make the functions reentrant. I use
lots of global data (large nested structs) to pass data around quicky.
The global structures are far too large (in size) for each of my
functions to maintain copies.

Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.
You will have to protect your global data structures so that
only a single thread access them at any given moment.

There are no "miracle" solutions, sorry.

--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32
Jun 27 '08 #5
Bit Byte wrote:
I am modifying some legacy code, to make the functions reentrant. I use
lots of global data (large nested structs) to pass data around quicky.
The global structures are far too large (in size) for each of my
functions to maintain copies.

Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.
Others have said there's no re-entrancy in C, but I don't
understand why they think that. A C function running in the
"main line" of the program might also be called from a handler
for an asynchronous signal, and if you want to do this you'll
need to be sure the function is re-entrant. And you can make
it so, with due diligence.

Aside from that limited situation, though, C has no notion
of "concurrent execution," nothing like multiple threads or
parallel processes or anything of that kind. If your problem
involves such beyond-C things then mere re-entrancy alone may
not be enough; you should probably seek advice on a forum like
comp.programming.threads.

But to the mechanics: Eliminating the global variables is
not in and of itself enough to make a function re-entrant, but
it's usually a necessary first step. If you've got a global
and a function that manipulates it:

int global;
void set_global(int new_value) {
global = new_value;
}

.... you can get rid of the global by giving the function an
extra argument that points to a non-global substitute:

void set_global(int *global, int new_value) {
*global = new_value;
}

This can become tiresome if there are a lot of globals to
be eliminated, and/or if the functions call each other a lot:
You'll get snarled passing a lot of pointer arguments all over
the place and probably getting some of them wrong. But much
of that can be smoothed over by using a struct:

/* Old */
int global1;
double global2;
char *global3;
void func(void) {
global1 = 42;
global2 = 42.0;
other_func();
}
void other_func(void) {
global3 = "XLII";
}

/* New */
struct globals {
int global1;
double global2;
char *global3;
};
void func(struct globals *gp) {
gp->global1 = 42;
gp->global2 = 42.0;
other_func(gp);
}
void other_func(struct globals *gp) {
gp->global3 = "XLII";
}

If there's a lot of this you may be tempted to use macros
to ease the transition:

struct globals { ... as above ... };
#define global1 gp->global1
#define global2 gp->global2
#define global3 gp->global3

.... which allows you to leave the existing functions almost
unchanged: The source still refers to plain old global2 and
so on, with the pointer automagically inserted. Do this if
you really, really feel you must -- but I've been down that
road, and just a few bends beyond where you can see it gets
rocky and rutted. Better to do the scut-work up front than
to maintain a hack for ever and ever.

--
Eric Sosman
es*****@ieee-dot-org.invalid
Jun 27 '08 #6
Eric Sosman wrote:
Bit Byte wrote:
>I am modifying some legacy code, to make the functions reentrant. I
use lots of global data (large nested structs) to pass data around
quicky. The global structures are far too large (in size) for each of
my functions to maintain copies.

Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.

Others have said there's no re-entrancy in C, but I don't
understand why they think that. A C function running in the
"main line" of the program might also be called from a handler
for an asynchronous signal, and if you want to do this you'll
need to be sure the function is re-entrant. And you can make
it so, with due diligence.

Aside from that limited situation, though, C has no notion
of "concurrent execution," nothing like multiple threads or
parallel processes or anything of that kind. If your problem
involves such beyond-C things then mere re-entrancy alone may
not be enough; you should probably seek advice on a forum like
comp.programming.threads.

But to the mechanics: Eliminating the global variables is
not in and of itself enough to make a function re-entrant, but
it's usually a necessary first step. If you've got a global
and a function that manipulates it:

int global;
void set_global(int new_value) {
global = new_value;
}

... you can get rid of the global by giving the function an
extra argument that points to a non-global substitute:

void set_global(int *global, int new_value) {
*global = new_value;
}

This can become tiresome if there are a lot of globals to
be eliminated, and/or if the functions call each other a lot:
You'll get snarled passing a lot of pointer arguments all over
the place and probably getting some of them wrong. But much
of that can be smoothed over by using a struct:

/* Old */
int global1;
double global2;
char *global3;
void func(void) {
global1 = 42;
global2 = 42.0;
other_func();
}
void other_func(void) {
global3 = "XLII";
}

/* New */
struct globals {
int global1;
double global2;
char *global3;
};
void func(struct globals *gp) {
gp->global1 = 42;
gp->global2 = 42.0;
other_func(gp);
}
void other_func(struct globals *gp) {
gp->global3 = "XLII";
}

If there's a lot of this you may be tempted to use macros
to ease the transition:

struct globals { ... as above ... };
#define global1 gp->global1
#define global2 gp->global2
#define global3 gp->global3

... which allows you to leave the existing functions almost
unchanged: The source still refers to plain old global2 and
so on, with the pointer automagically inserted. Do this if
you really, really feel you must -- but I've been down that
road, and just a few bends beyond where you can see it gets
rocky and rutted. Better to do the scut-work up front than
to maintain a hack for ever and ever.
Good advice indeed. Only bit I don't understand is your last statement:
"Better to do the scut-work up front than to maintain a hack for ever
and ever."

I thought that 'wrapping" the globals in a struct and using macros to
access fields (posibly with mutex/semaphores) was a good idea - but
after you last statement, I am not sure if you mean it is a 'hack' -
since you have been down this route already, your views are of interest
to me ...
Jun 27 '08 #7
Bit Byte wrote:
Eric Sosman wrote:
>[...]
If there's a lot of this you may be tempted to use macros
to ease the transition:

struct globals { ... as above ... };
#define global1 gp->global1
#define global2 gp->global2
#define global3 gp->global3

... which allows you to leave the existing functions almost
unchanged: The source still refers to plain old global2 and
so on, with the pointer automagically inserted. Do this if
you really, really feel you must -- but I've been down that
road, and just a few bends beyond where you can see it gets
rocky and rutted. Better to do the scut-work up front than
to maintain a hack for ever and ever.

Good advice indeed. Only bit I don't understand is your last statement:
"Better to do the scut-work up front than to maintain a hack for ever
and ever."

I thought that 'wrapping" the globals in a struct and using macros to
access fields (posibly with mutex/semaphores) was a good idea - but
after you last statement, I am not sure if you mean it is a 'hack' -
since you have been down this route already, your views are of interest
to me ...
Anything to do with the "posibly [sic] with mutex/semaphores"
part belongs in comp.programming.threads, not here, since as I
mentioned before the C language's limited notions of simultaneity
don't extend to multi-threaded or even multi-process programs.

Now, about macros of the kind I illustrated. The first bit
of hackishness is the introduction of an "assumed" identifier,
the `gp->' part. If the function argument isn't named literally
`gp' the thing blows up. A person reading the code will see an
argument named `gp' but will not see it used anywhere in the
body of the function, and may get confused by the apparently
unused argument. A person studying the code in a debugger will
be unable to examine or alter what seems on its face to be a
perfectly normal `global2' variable. And so on. You may save
some lexical work up front, but with those savings you buy a
nagging irritation that keeps on paying its unwelcome dividends.

A coding style guide developed by a bunch of pretty highly-
respected C folks puts it this way: "Don't change syntax via
macro substitution. It makes the program unintelligible to all
but the perpetrator." You, it seems, are even now struggling
with the decisions made by the long-ago authors of your "legacy
code," and probably complaining or at least muttering about the
lack of clarity resulting from some of those decisions. Have
mercy on the person who in turn will follow you through this
code, and seek not to be on the receiving end of his mutterings
and complaints. Remember: Source code is read by compilers but
also by programmers, and the latter are the more important
audience.

--
Er*********@sun.com
Jun 27 '08 #8
rio
What is "Reentrant code"?
A function that use all its data in the stack i.e. automatic
variables and arguments, is reentrant?
A function that use all its data that came from a reentrant malloc
function is reentrant?

Thank you

Jun 27 '08 #9
In article <48***********************@reader4.news.tin.it>, rio <a@b.cwrote:
>What is "Reentrant code"?
A function that use all its data in the stack i.e. automatic
variables and arguments, is reentrant?
A function that use all its data that came from a reentrant malloc
function is reentrant?
Suppose a routine is executing, and -somehow- during the middle
of execution, the execution gets suspended and -somehow- the
same routine gets called *while the original is suspended*.
Then if the routine works properly in the new call and exits
clealy, and upon being resumed, the suspended version continues
to work properly, then the routine was re-entrant.

In the above discussions, I omitted the mechanisms by which
the execution of a routine might get suspended and yet a new instance
of it be started. In pure standard C, the only way it can happen is
if the routine is called (directly or indirectly) as a signal handler
as a result of a system-generated signal or as a result of a raise()
call. In C that is not quite as pristine, there may be system
mechanisms (such as threads) that allow such things to happen.
--
"This quitting thing, it's a hard habit to break once you start."
-- Walter Matthau
Jun 27 '08 #10
On Jun 17, 9:49*am, rober...@ibd.nrc-cnrc.gc.ca (Walter Roberson)
wrote:
In the above discussions, I omitted the mechanisms by which
the execution of a routine might get suspended and yet a new instance
of it be started. In pure standard C, the only way it can happen is
if the routine is called (directly or indirectly) as a signal handler
as a result of a system-generated signal or as a result of a raise()
call.
You forgot recursion.
Jun 27 '08 #11
In article <57**********************************@k30g2000hse. googlegroups.com>,
Kaz Kylheku <kk******@gmail.comwrote:
>On Jun 17, 9:49=A0am, rober...@ibd.nrc-cnrc.gc.ca (Walter Roberson)
wrote:
>In the above discussions, I omitted the mechanisms by which
the execution of a routine might get suspended and yet a new instance
of it be started. In pure standard C, the only way it can happen is
if the routine is called (directly or indirectly) as a signal handler
as a result of a system-generated signal or as a result of a raise()
call.
>You forgot recursion.
I was thinking about recursion, but I got up hours too early today and
somehow it dropped out of my thought processes when I was composing that.

Recursion is relevant to the topic of re-entrancy; I think I was
focussed a little too much on the "suspension" in terms of interruption,
especially as in the other cases (signals, threads) the routine is left
in an indeterminate state, whereas in recursion there is always a
sequence point before the call so the routine's state will be more
stable.
--
"The slogans of an inadequate criticism peddle ideas to fashion"
-- Walter Benjamin
Jun 27 '08 #12
On Jun 17, 12:02 pm, Keith Thompson <ks...@mib.orgwrote:
vipps...@gmail.com writes:

[...]Re-entrancy doesn't have to do anything with threads or thread safety,
but indeed ISO C doesn't mention thing such as 'reentrancy', 'threads'
etc.

[...]

It does, but only briefly.

C99 7.1.4p4:

The functions in the standard library are not guaranteed to be
reentrant and may modify objects with static storage duration.

footnote:

Thus, a signal handler cannot, in general, call standard library
functions.

There's also an index entry for "reentrancy", pointing to 5.1.2.3
(Program execution) and 5.2.3 (Signals an interrupts) as well as
7.1.4.
Thanks Keith, it's just one of those things I /think/ I know about C.
I'm glad people here spot them. I'll remember it from now on.
Jun 27 '08 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Adrian Parker | last post by:
For some reason when I call validateFields before .Update (see below), I get this error: "Consumer's even handler called a non-reentrant method in the provider" However if I comment out the...
0
by: Martin B | last post by:
Hallo to everyone! Problem: -------- GridView Exception: reentrant call to the SetCurrentCellAddressCore function System: ------- WinXP Professional, english, .NET Framework 2.0 Beta...
6
by: junky_fellow | last post by:
what are reentrant functions? What are the characteristics of a reentrant code ? what things should be kept in mind while writing a reentrant code ?
2
by: TheOne | last post by:
Would anyone please point me to a list of reentrant GNU C/C++ library functions? I have searched a lot on the web for it but without any success. Man page of signal(2) has listed system calls...
9
by: TheOne | last post by:
Would anyone please point me to a list of reentrant C library functions? I want to know which C library functions are safe to use inside a signal handler across all platforms. Does GNU C library...
2
by: a | last post by:
Hi, I have the following setup: PHP 5.1.x on Apache 2.x on Windows XP. A php script receives data from a form upon user submit, and then execs a Windows process, which may take some time to...
1
by: jj_online | last post by:
This is not a C++ specific issue. However, I am trying to implement a readwritelock in C++ and hence would like to get help from this group. a readwritelock allows shared lock among all readers...
17
by: fmassei | last post by:
Dear all, I'm trying to put some old code in a portable, cross-platform library and I'm facing a big problem: is there a standard, platform- independent way to write a reentrant function that...
5
by: Roland Mainz | last post by:
Hi! ---- Does anyone here know any XML parsers which are reentrant, threadsafe, maintained (e.g. the project should still be active+alive) and written in ANSI-C (libxml2 is unfortunately not...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.