The BASICS class library was written to create a uniform class API for system services frequently used by control programs. Most operating systems support these services but have their own API structure which makes writing code for multiple platforms cumbersome. BASICS is intended to hide these differences, but also add things missing on a specific platform.
This class library is used by the High Energy Physics experiment CLEO, located at Cornell University, Ithaca NY. Therefore the scope of the implemented classes is limited to the use in a monitoring and control system consisting of C++ objects in a networked environment. But I hope it is useful for similar purposes elsewhere.
Version 1.2 supports the following platforms:
The BASICS source comes with a directory tree that can contain other packages related to the CLEO experiment. When you unpack the tar file for the BASICS package, the root directory contains a configure script to create the correct Makefiles for your platform. The source itself can be found in `src/basics'.
Follow the global steps listed here to compile and install BASICS. Also check comments about special considerations for some platforms at the end of this chapter
During the configuration process certain choices are made depending on the capabilites of the C++ compiler and installed third-party/system software. These choices are made by setting C preprocessor macros in the file `sc_config.h' (located at the root of the directory tree).
To insure the correct use of these flags all header (.hxx) and all source files (.cxx) must include the file `sc_stddef.h' as the first header before any other statement! This file contains a `sub-include' command to read `sc_config.h' and subsequent definitions and other macros, some of them depending on the taken choices!
Additionally, some BASICS functions (calling system routines) return a numeric value reflecting the success or not success of this call. Following the UNIX convention, a `0' (zero) means success and a non-zero value means error, decoding the reason for this error (the `error condition').
On the other hand, there are functions returning numbers,
that actually represent a boolean value.
In this case a 0 (zero) means false
signalling an error!
In the same category are functions returning a pointer,
here NULL reflects an error.
In the BASICS library, we will clarify this situation
by using two typedef commands in the `sc_stddef.h'
file:
typedef int Boolean;int.
All functions returning an int representing a boolean value
will have a prototype with a Boolean return type.
Additionally, the macros TRUE and FALSE are defined
to give the correct value in a return(); statement
of such a function.
typedef int FuncReturn;OKAY is defined to give the correct value
for the condition `no error'.
NULL to check for an error
by comparing the returned pointer to this value.
Header file: `bsobject.hxx'
The main purpose of this class is to name class instantiations, keep a run-time record of RCS version tags, and provide simple means to create readable debug output.
All following functions are useful, when called inside a class method of a class derived from `bsobject'. They will report the file name and line number from where they were called, and the name if the instance, set at construction time.
Additionally, BCO_cout() is a static function of `bsobject',
that you can call anytime.
It returns the `current output stream' of the BASICS library,
which is cout by default,
or any output stream set with setOutput().
It will not insert any instance or code line information
into the stream.
Example:
class example : virtual public bsobject
{
example(const char* name) :
bsobject(name,
"$Id: basics.texi,v 1.5 1998/04/16 22:50:41 ahw Exp $") {}
};
This code shows,
how to pass the name of an instantiation to the bsobject base class,
and how the RCS id string is generated.
The derived classes should normally use the virtual public
base class qualifiers.
This generates a single bsobject instantiation,
even if a class has multiple base classes,
each having bsobject in their class tree.
bsobject class with no string parameters.
In rare cases the class information is not needed,
so we also provide a "default constructor".
bsobject data part
that contains the name string for this instantiation.
This string is also used for the debug output,
so you know,
which instantiation of a certain object has produced it.
bsobject data part
that contains the RCS id string.
All objects have one RCS id. Therefore the "last" object in the inheritance tree sets this value, since its constructor is called last.
BCO_...() and CCO_...()
to the given output stream
(see section Debug Help for Non-Class Functions for the CCO_...... functions).
TRUE adds the date to the output.
Example:
BCO_error()<< "Could not open file!" <<endl;-|Example.cxx:123: **ERROR**: Could not open file!
Example:
BCO_warning()<< "Configuration data stale!" <<endl;-|ConfigDB.cxx:1202: Warning: Configuration data stale!
Example:
BCO_info()<< "Checking HV..." <<endl;-|Interlock.cxx:410: Info: Checking HV...
All these messages are switched off,
if during compile time the switch _DEBUG is not defined.
Example:
BCO_debug()<< "List was empty." <<endl;-|Example.cxx:132: Debug (Test): List was empty.
Example:
BCO_cout()<< "Version 1.03 started!" <<endl;-|Version 1.03 started!
This method uses the `runtime' library internally to extract the parameters from the given runtime option(s). (see section Runtime Option Parsing)
bsobject does not duplicate the string given in the
constructor!
It only copies the pointer value.
Since almost all the time,
the name string is given as a fixed string (e.g. using "Example"),
this is no problem and saves time.
symName only the reference is stored,
since this id is always a fixed string.
Header file `btime.hxx'
It is not allowed to create an `empty' btime class
instance!
Always use a provided static function to create it, like getNow().
All functions with a name starting with get are in fact static
and return a copy of a valid btime instance.
Use these functions to initialize or set any variable of type btime.
This can be done at declaration time,
calling the copy constructor to store the data in the local variable.
Example:
static btime midnight_1_1_1970 =
btime::getFromUTCText("UTC: 01/01/1970 00:00:00");
There are many conversion and comparison operators to allow for
a convenient user API of a btime instance.
Its main use inside BASICS
is the "tagging" of debug output generated by bsobject
functions with the current date/time (see section The Cosmic Base Class).
The correctness of local date/time output depends on the correct choice of the timezone you are working in. Internally, no time zones or Daylight Saving Time periods are used, only Unversal Time Coordinated (UTC) times!
Normally, the configuration steps will use the timezone found on the machine this library was compiled on and compile it into the code as default. But you can force the `configure' script to use a different timezone with the option `--with-timezone'. See section Time Zone Problem how a timezone is specified.
btime.
Set virtual to correctly call destructors of derived classes.
btime
that contains the current time.
This is a costly method, so if you want to use a temporary btime variable avoid using this function to fill it.
btime instance.
This structure is machine-dependent.
btime instance.
JDint represents the number of the day after the start of the
Julian calendar.
JDfraction represents the fractional part of that day.
Note: Use this method to fill a temporary btime variable
btime tmp = btime::getFromJulianDate(0, 0);
Remember, that this (astronomical) time representation uses the Universal Time Coordinated (UTC) time and starts a day at 12:00 noon, UTC.
The format of the string is
"<TimeZone>: MM/DD/YYYY HH:MM:SS.ssssss".
Timezone is a string describing the current location's time zone.
(see section Time Zone Problem)
It will complain, if the strings do not match.
This might also happen,
if the given time is actually in a different DST period
than indicated by this string.
The format of the string is
"UTC: MM/DD/YYYY HH:MM:SS.ssssss".
tm structure
into a btime instance.
You can also provide sub-seconds expressed in usec.
It is assumed, the date and time was given in the UTC time zone.
tm structure
into a btime instance.
You can also provide sub-seconds expressed in usec.
It is assumed, the date and time was given in the local time zone
setup inside of the time library (see section Time Zone Problem).
btime instance.
You can also provide sub-seconds expressed in usec.
This is useful for astronomical programs using the `epoch 2000' as reference.
btime instance
representing a time difference of multiple of seconds.
Useful in conjunction with the `+', `-', and comparison operators.
Example:
btime timer = btime::getFromJulianDate(2450781l, 0.5000);
timer += btime::aSecond();
The default parameter value creates exactly 1 second.
btime instance
representing a time difference of multiple of minutes.
Useful in conjunction with the `+', `-', and comparison operators.
Example:
btime timer = btime::getFromJulianDate(2450781l, 0.5000);
timer += btime::aMinute();
The default parameter value creates exactly 1 minute.
btime instance
representing a time difference of multiple of hours.
Useful in conjunction with the `+', `-', and comparison operators.
Example:
btime timer = btime::getFromJulianDate(2450781l, 0.5000);
timer += btime::aHour();
The default parameter value creates exactly 1 hour.
btime instance
representing a time difference of multiple of days.
Useful in conjunction with the `+', `-', and comparison operators.
Example:
btime timer = btime::getFromJulianDate(2450781l, 0.5000);
timer += btime::aDay();
The default parameter value creates exactly 1 day.
btime instance
representing a time difference of multiple of weeks.
Useful in conjunction with the `+', `-', and comparison operators.
Example:
btime timer = btime::getFromJulianDate(2450781l, 0.5000);
timer += btime::aWeek();
The default parameter value creates exactly 1 week.
Example:
btime timeDiff = timerNow - timer;
cout << timeDiff.inDays()<<"d = "<<timeDiff.inHours()<<"h" << endl;
JDint represents the number of the day after the start of the
Julian calendar.
JDfraction represents the fractional part of that day.
Remember, that this (astronomical) time representation uses the Universal Time Coordinated (UTC) time and starts a day at 12:00 noon, UTC.
struct tm for the UTC time zone,
and (if needed) the sub-second part expressed in usec.
struct tm for the local time zone,
and (if needed) the sub-second part expressed in usec.
preciseTime.
time_t value,
representing the number of seconds since Jan 1st, 1970, midnight UTC.
Format: <TimeZone>: MM/DD/YYYY HH:MM:SS.ssssss
Since time zones and daylight saving times are correctly
handled, <Timezone> will be the currently used zone.
(see section Time Zone Problem)
Note: This call overwrites the pointer text.
The new value points to a character string which was allocated
on the free store.
The caller has to free this memory with "delete [] text" later!
Format: UTC: MM/DD/YYYY HH:MM:SS.ssssss
Note: This call overwrites the pointer text.
The new value points to a character string which was allocated
on the free store.
The caller has to free this memory with "delete [] text" later!
double with enough sub-day resolution.
Used by many astronomical tools.
MJD is defined as mjd = jd - 2440000.
There is nothing worse than time zones and Daylight Saving Times!
But we stopped whining,
and tried to implement a rudimentary management of this issue
into the btime class.
It might not work for all, but
for the American and European zones it should be sufficient.
Also, it can not accomodate for changes in the DST rules
that happened over the last 100 years.
We only try to manage the current rules, that's hard enough.
TZstring contains the following information:
Mmm:ww:dd
M = The letter M. If there is ever a need for different rules.
mm = Month of change. It's a number between 1 and 12.
ww = Week of change. It's a number betweeb 1 and 5.
5 means `the last week' of the month.
dd = Weekday of the change. It's a number between 0 and 6.
0 means Sunday, 6 means Saturday.
Example:
btime::setTimezone("EST5EDT:M4.1.0:M10.5.0");
This sets the time zone to Eastern US standard,
with the DST period starting at the first Sunday in April,
(2:00 am EST by default) and ending the last Sunday in October
(also 2:00 am EST by default).
A default value is already set at compile time and is selected at configuration time.
btime.
btime.
btime.
It is TRUE if the represented time is during
the Daylight Savings Time (DST) period of the time zone set for this instance.
btime
is setup for.
During Daylight Savings Time (DST) period the time zone might have a different name.
Then it will return that name.
basics::init, which in turn calls this method.
The option -TZ with a string as parameter is recognized
by this function.
It uses the `runtime' library internally to extract this parameter from the given runtime option. (see section Runtime Option Parsing)
Header file `runtime.hxx'
basics:: to avoid
messing with the global namespace.
They are meant to be called in the main part of a program to retreive any valid option given to the started process at run time. Additionally, they provide a `help' facility that describes the option(s) if the user starts the program with the `command' `-help'.
To signal the existence of an option,
or that `-help' was found
(which normally should terminate the program gracefully
after printing the help lines)
three return values are provided
(coded in an enum): `NotFound', `Found', and `Help'.
VxWorks: There is a special function for VxWorks
to transform a given string into the UNIX standard
variables argc and argv:
`runtimeTransform'.
Since VxWorks does not support a function main in
a program, use a string parameter in the function
that is called to start a program.
You should use `#if ... #endif' commands
in your code to make this work properly!
Example:
#if defined(__vxworks)
extern "C" int program(char* params);
int program(char* params)
{
int argc;
char** argv;
basics::runtimeTransform(params, argc, argv);
#endif
#if defined(__unix)||defined(_WIN32)
int main(int argc, char **argv)
{
#endif
...
}
enum to return the parsing result to the caller.
Possible values are
NotFound: The given options string was not found.
Found: The given option string was found and the
variable set accordingly.
Help: The string `-help' was found as an option.
FALSE or `off' if the options string is absent,
and TRUE or `on' if the options string is present
No further parameter is needed!
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (int) variable as `variable'.
The function will remove the option from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
(In this special case the return value corresponds directly with the value of `variable'.)
Example:
basics::Result res;
int onOff;
res = basics::runtime_switch_opt(argc, argv,
"-on", "Lamp switch",
onOff);
SPACE
and then a string representing an integer numerical value.
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (int) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
int number = 1;
res = basics::runtime_int_opt(argc, argv,
"-times", "multiply by",
number);
SPACE
and then a string representing an integer numerical value.
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (long) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
long date = 2450034l;
res = basics::runtime_long_opt(argc, argv,
"-JD", "Julian Date",
date);
SPACE
and then a string representing a non-negative integer numerical value.
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (size_t) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
size_t chunk = 16;
res = basics::runtime_size_t_opt(argc, argv, "-chunk",
"chunk size",chunk);
SPACE
and then a string representing a time.
The time string can have multiple formats:
All combinations are allowed and found until the next option (marked with a `-') or the end of option array is reached.
Note: If the library is compiled for it, the date string will have the day and month field swapped! Check the configuration file `sc_stddef.h' or read the explanation given by the `-help' switch.
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (tm) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
time_t now = time(NULL);
struct tm* when = localtime(&now);
res = basics::runtime_tm_opt(argc, argv,
"-start", "Start time",
*when);
SPACE
and then a string representing an real numerical value.
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (float) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
float weight = 100.0;
res = basics::runtime_float_opt(argc, argv, "-weight",
"weight of the users (in kg)", weight);
SPACE
and then a string representing an real numerical value.
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (float) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
double speed = 65.0;
res = basics::runtime_double_opt(argc, argv, "-limit",
"speed limit (in mph)", speed);
SPACE)
and is left unchanged if the options string is absent,
and set to the given value if the options string is present.
After the option string has to follow a SPACE
and then a string representing any text
Pass the option string as `option_name',
the explanation as `variable_name',
and the actual (float) variable as `variable'.
The function will remove the option and the parameter
from the `argv' array
if it is found (adjusting `argc' also)
and return `Found'.
Otherwise it will return `NotFound'
or `Help', if the option string `-help' was found.
Use this return value for changing the program's behaviour, or just use the default value you set before you called this function.
Example:
basics::Result res;
char* device = "/dev/null";
res = basics::runtime_string_opt(argc, argv, "-dev",
"output device name", device);
Header file: `console.hxx'
They are also declared with the extern "C" keyword,
so that any C code can call them, too.
The text string is given the same way as for printf,
first a format string and then variable number of parameters.
All functions names correspond to the output methods
in the bsobject class,
they only start with CCO instead of BCO.
Secondly, you have to provide the macros __FILE__
and __LINE__ "by hand" when you call one of these functions.
Comment: The output of these functions can not be redirect
but go all to stdout.
errno variable to generate a human--readable
text containing the error.
Example:
CCO_error(__FILE__,__LINE__,"Reading configuration.\n");-|HV.cxx:490: file not found: (C): Reading configuration.
Example:
CCO_warning(__FILE__,__LINE__, "User `%s' unknown! Hacking attempted?\n", password->user);-|Password.cxx:312: warning (C): User `ahw' unknown!\ Hacking attempted?
Example:
CCO_info(__FILE__,__LINE__,"Comitting to %s.\n", state);-|RunControl.cxx:312: info (C): Comitting to Paused.
All these messages are switched off,
if during compile time the switch _DEBUG is not defined.
Example:
CCO_debug(__FILE__,__LINE__,"List %s was empty.\n", group);-|Alarm.cxx:132: debug (C): List Alarm was empty.
printf,
implemented for symmetry reasons.
Example:
CCO_printf("Going home...\n");-|Going home...
Header file: `xitman.hxx'
private BEX_func_list, virtual public bsobject
The exit manager class BEX_xitman is a list of C functions
that get called when the "main thread" of a program
exits or receives certain signals.
The list is setup using the "singleton" behavior, which means the constructor checks for the existence of this list in a place shared between all threads inside the program. Only if it does not exist, it will be created from scratch. Otherwise it will use the reference to the existing list.
The order of the added functions is preserved, and when the exit manager is "active" it will call all functions in the reverse order. Rule Always add a new function after you used resources! Then, these resources get cleaned up after your new `cleanup function' was called.
class BEX_xitman *xm;
// Get reference to exit manager, create it if necessary.
xm = new BEX_xitman;
assert( xm != NULL);
// Insert destruction into exit manager
if (-1 == xm->add(BSP_removeResources))
BCO_warning() << "Add function to exit manager failed" << endl;
// Remove reference. The real manager is static and
// will not be touched
delete xm;
Note: In order to use the BASICS library in a shared manner
in VxWorks, normal user programs must not add any cleanup function
to the xitman directly!
Use the ANSI function atexit for this purpose!
Create the exit function list or return a reference to it.
Create the exit function list or return a reference to it.
It does not remove the exit function list, so it is a dummy function for symmetry reasons. The list is removed when the thread exits, only.
The function's signature is fixed to return no value, and to receive no parameters.
It checks the flag iamAlive and performs the following
actions if it is FALSE:
BEX_cleanup as function to
be called when the thread exits.
BEX_signalexit)
which will call exit after some informational output.
This in turn will call BEX_cleanup to stop the thread.
iamAlive to TRUE.
TRUE after the constructor was called for the
first time.
It is needed to implement the "singleton" behavior of the class.
It is used by BEX_xitman by having it as a parent class.
The list entries itself are stored in a globally accessible
place so they are shared between all threads.
Comment: The following functions are changing the internal
state of BEX_func_list and are therefore not thread safe.
However, this is no problem at all,
since these functions are used by the Operating System
when performing the thread exit,
so there is no other thread using this class!
NULL if list is empty.
NULL if it reached the end.
Header file: `bsemaphore.hxx'
virtual public bsobject, private BSP_SBase
A class implementing a "binary semaphore".
This semaphore has two states: full or empty.
Consequently, it has two basics methods: take and give.
If the semaphore is "empty" a call of take will block
the calling thread until the semaphore gets filled by
some other thread.
If multiple threads are waiting for the same semaphore,
this give action will activate a single thread
and keep the others blocked.
This happens because the first action of the activated
thread is to empty the semaphore.
Which one of the threads is activated is not defined.
In contrast to a mutual exclusive semaphore,
the give method can be called by any thread,
not only by the one that called take last.
It is virtual so we can call the correct destructor of any derived class.
The return value reflects the success of the action.
Example:
BSP_Binary start;
while (TRUE)
{
start->take();
action();
}
This example shows an infinite loop that executes once per "event".
The "event" is communicated to this thread by any other thread using
give on the semaphore start.
The return value reflects the success of the action.
TRUE if the semaphore is in the "empty" state,
FALSE otherwise.
Example:
// Wait for timeout or actions through the semaphore
for (int i = 0; i < myRate/2; i++)
{
BPT_sleep(2);
if (!mySynch->isEmpty())
{
BCO_debug()<< "Got wakeup call!" <<endl;
mySynch->take();
break;
}
}
This code waits for a signal through the semaphore,
but also wants to stop after a timeout.
So we avoid blocking the thread by only using isEmpty
to check for the state of the semaphore.
virtual public bsobject, private BSP_SBase
A class implementing a "mutual exclusive semaphore".
Similar in behavior as the BSP_Binary class,
once the semaphore is "locked" it can only
by "unlocked" by the same thread.
lock will block the calling thread,
if the semaphore is already "locked".
For this semaphore the same rules apply for
activating threads after an unlock call
as for BSP_Binary
(see section Semaphore Classes).
BSP_Mutex protect;
protect->lock();
protected->change();
protect->unlock();
This example shows a class protected which is "guarded" by
the semaphore protect.
Only one thread can execute the function change at any time.
(This code is not a good template, since somebody could call
change without using the semaphore.
It is much better, to derive the protected class from
BSP_Mutex or have a semaphore as data member
and then let change test that it is actually locked.)
It is virtual so we can call the correct destructor of any derived class.
The return value reflects the success of the action.
The return value reflects the success of the action.
TRUE
if it is locked, FALSE otherwise.
One of the most important design issues of this class is that it has the exit function used by the exit manager as a friend of the class.
Since all semaphore classes are derived from BSP_SBase
the contruction of any of those will
BSP_SBase, eventually
registering the cleanup function.
memorizeSemaphore when the
system resources are allocated in its function code.
TRUE after the constructor was called for the
first time.
It is needed to flag whether the exit function is installed
using an BEX_xitman
(see section Exit Manager Class)
instance.
Header file: `bthread.hxx'
virtual public bsobject
A class implementing a pseudo--POSIX thread. Although most of the supported platforms are supposed to have a POSIX thread library, there are multiple "flavors" of threads. This class presents an API which contains similar ideas but is tailored to the specific need of controll threads.
There are two ways of using this class:
execMethod.
class MyThread : public BPT_Pthread
{
private:
void* execMethod(BPT_ArgArray* Args);
public:
MyThread(const char *name) :
bsobject(name,
"$Id: basics.texi,v 1.5 1998/04/16 22:50:41 ahw Exp $"),
BPT_Pthread() {}
~MyThread() {}
};
This code will later define the function MyThread::execMethod
which will be executed when the thread is started.
extern "C" void* thread_1(BPT_ArgArray* );
BPT_Pthread c_thread("doomed", thread_1);
Here the constructor receives the function pointer thread_1,
and this function is called when this thread is started.
The thread is not started yet.
The function startThisThread is used for this,
after the user has possibly changed same parameters how
the thread is executed.
f.
The return value reflects the success of this call.
With this call the parameter number num is set to
the value new_arg.
The type of this parameter allows pointers and
numbers with their size smaller than a pointer to be passed
to the thread function.
The parameters are recorded in the class BPT_ArgArray,
which has space for upto 10 parameters.
This maximum number is the OS limit of the VxWorks system,
so we have to enforce it anywhere.
However, it should never be any real constraint.
Example:
c_t.setArgument(0, (void *)20);
c_t.startThisThread(0);
b_t.setArgument(0, (void *)&c_t);
b_t.startThisThread(0);
BPT_ArgArray class.
Example:
void *OtherThread::execMethod(BPT_ArgArray *Args)
{
BPT_Pthread* toJoin;
if (Args)
BPT_GetNextArg(Args, (void **)&toJoin);
else
{
printf("NULL ptr argument\n");
return("Not started");
}
...
}
0 is the default value.
The return value reflects the success of the method.
Example:
BPT_Pthread* myClient;
myClient = new GroupClientThread(myDataList, myThreadName);
myClient->startThisThread(0);
How the sharing of the CPU time is performed is not defined.
You should not assume anything or
"the worst case" for you application.
Use BPT_sleep to relinquish the CPU,
if necessary.
TRUE if there is a running thread for this object,
FALSE otherwise.
void*.
Normally, a thread can only be cancelled at a cancel point. These are either some selected system library calls, or a certain point or area of the thread's code.
This behavior can be changed to
This feature is needed to protect threads from being stopped at places where they are still reserving resources that would not be released, if the thread would be cancelled at this point. Unfortunately, not all platforms support this mechanism, so the methods are empty functions for those systems.
All following functions are class static functions
that can be called from inside the thread function without any
reference to an instance of BPT_Pthread.
Example:
GroupClientThread::~GroupClientThread()
{
cancelThisThread();
delete myInterface;
}
This shows, how you can make the destructor of a class derived
from BPT_Pthread cancel any active thread of this instance.
Example:
boa->obj_is_ready(myInterface);
BPT_Pthread::startCancelArea();
boa->impl_is_ready();
return("X");
This shows the code fragment of a server program going into
an infinite event loop (impl_is_ready()).
Before you do this,
you must allow for cancellation,
which is done here by calling startCancelArea().
startCancelArea.
Cancellation are restricted to selected oprating system calls
This function is declared with extern "C",
so it can be called from a C function running as thread.
BPT_ArgArray
containing the arguments for this thread function
It sets up the correct function pointer to call the "main function", and creates the default attributes for the thread instance.
When you use BPT_Pthread::setArgument to set parameters
before activating a thread,
all the values you give are stored inside an instance
of BPT_ArgArry.
A pointer to this instance is then passed on
to the "main function".
The easiest way of retreiving those values is
calling the methods of this object,
which return the type void* and assign
it to the expected type.
There is no type--checking possible.
Example:
long max = 10;
if (Args)
{
void* arg_max;
BPT_GetNextArg(Args, &arg_max);
max = (long)arg_max;
}
You can either retreive the parameter values using
the getArg method of the class,
or use the (C visible) friend BPT_GetNextArg function.
It will return values one after the other.
Again it is a class static function,
so any C program can call it,
receiving the BPT_ArgArray instance as a pointer value
as its first parameter.
This way, C programs running as thread functions
can use a type void * as parameter and retrieve
parameters without being compiled as C++ code.
max entries.
num.
num,
into the memory pointed to by arg.
BPT_GetNextArg.
void*.
Allocated at construction time with the size maxArgs.
Header file: `bsocket.hxx'
virtual public bsobject
The base class to all socket classes. It can be used directly, but then needs more setting up to work with the correct address family and protocol.
These classes are useful to create networked connections, if a CORBA interface is not possible or has large overhead. With other words, this should be a rare case for the environment of CLEO! Try to avoid this, since these connection introduce hardware dependencies, like host names and IP addresses...
No system resources are allocated or sockets openened at construction time.
The return value reflects the success of the method, it does not return the socket descriptor.
sock.
Comment: The type of the argument is platform dependent!
Destructing the object only,
does not close the connection properly.
Always use close before deleting a socket object!
optionValue.
The name and level of the option is set by
numeric values found in the header files of the
used socket type.
optionLen is used to communicate the maximum memory size
usable to copy the value.
int typed values.
These are the most common ones,
so it is nice to have an easier API to access them.
optionValue.
The name and level of the option is set by
numeric values found in the header files of the
used socket type.
optionLen is used to communicate the memory size used
by the value given.
int typed values.
These are the most common ones,
so it is nice to have an easier API to work with them.
listen for starting that),
a call to this method will block the thread until
a "client" has connected to this socket port.
The thread will be activated
and the returned BSO_socket instance
is used to setup a new socket port to communicate
with the new client.
Example:
BSO_StreamSocket test("Sock1");
BSO_StreamSocket newConn("Session");
...
while (TRUE)
{
if (-1 == test.accept(newConn)) break;
CCO_printf("Got a connection!\n");
newConn.printInfo(TRUE);
cnt = 0;
do
{
...
}
CCO_printf("Close connection after %d messages.\n", cnt);
newConn.close();
}
This example uses a derived class of BSO_Socket
that automatically uses AF_INET address family (=TCP/IP),
and the SOCK_STREAM protocol.
accept for a long time,
requests are queued up until this number is reached.
In this state connect requests fail until the server connects to one of the
clients pending.
You can only listen to connections after you used bind
to set the server's socket address.
AF_INET address family.
For this family
the IP address (in host format),
and the socket port number
makes up an address.
AF_INET address family.
This version will use the Domain Name Service
to find the correct IP octet for the given host.
AF_INET address family.
This version will use the IP address of the host it is executed on.
Example:
class BSO_StreamSocket test("Sock1");
test.create();
if (-1 == test.bind(16100))
{
CCO_error(__FILE__,__LINE__,"error calling bind.\n");
return(-1);
}
AF_INET address family.
octet is the IP address in host format.
AF_INET address family.
hostName is the name of the host to connect to.
It will be translated into an IP address using DNS.
Example:
BSO_StreamSocketND test("Sock1");
if (-1 == test.create()) return(-1);
if (-1 == test.connect(16100, argv[1])) return(-1);
...
This example uses a derived class of BSO_Socket
setting up a AF_INET connection.
func depends on the device driver and is defined
in a header describing this device.
Use only for special cases, since not all of the functions are available on all devices.
buffer.
If no data is available the thread will block until
data is sent from the other side of the socket.
bufferLength is the maximum number of bytes
that can be written to the buffer.
If a "message" is too long for the buffer
parts of it may be dropped depending on the type of the socket.
The flags parameter can be used
to read "out--of--band" data
or "peek" into the socket read buffer to check for available data.
The returned number gives the actually received bytes.
Example:
char oneMessage[1024];
oneSize = newConn.receive(oneMessage, sizeof(oneMessage), 0);
The example reads a message from the socket.
listen/accept,
but clients can write to it at any time.
This method will return the address of the client
sending the "message" stored in buffer.
AF_INET,
where an address consists of an "IP octet" and a port number.
buffer
with the length bufferLength through the socket
to the "other side".
Again, this socket has to be in the "connected" state.
You can use flags to send the data
as a "out--of--bounds" message.
The return value reflects if the call was successful.
Example:
for (countMessages = 0; countMessages < 10; countMessages++)
{
test.send(oneMessage, sizeof(oneMessage), 0);
}
AF_INET address family.
A call to close on the socket will shutdown
the socket in both directions, too.
The verbose switch will increase the amount of
output even more, if set to TRUE.
Returns TRUE, if socket is no longer properly connected.
== operator.
virtual public BSO_socket
Sets the address family and protocol to the values needed for TCP/IP connections when constructed.
All methods of BSO_Socket are inherited (what else...).
AF_INET,
and the protocol to SOCK_STREAM.
It also names the instance using name.
virtual public BSO_socket
Sets the address family and protocol to the values needed for TCP/IP connections when constructed. Also switches off the TCP "delay mechanism", which enhances performance by concatenating messages into one IP packet if possible.
All methods of BSO_Socket are inherited (what else...),
but create is overwritten to set TCP_NDELAY option
in created socket.
AF_INET,
and the protocol to SOCK_STREAM.
It also names the instance using name.
BSO_Socket.
This function sets the TCP_NDELAY option
after the socket is created,
and before it returns.
sock.
Comment: The type of the parameter sock is platform dependent!
virtual public BSO_socket
Class to instantiate a socket using the UDP protocol. UDP is especially useful to broadcast messages to all nodes in an IP domain.
AF_INET socket using
the SOCK_DGRAM protocol.
Give this instance also a name.
Header file: `messageq.hxx'
Library classes to provide message queues visible to all threads/processes on a host.
Class with a pseudo--POSIX API implementing a "Message Queue".
You can use a message queue to send complex messages to threads in the same process/node avoiding the overhead of a socket. The drawbacks are more restrictive resources and no way to communicate with other nodes using this class.
The API is modelled to resemble the interface of a BSO_socket
class.
name.
max_msg messages,
with a length of msg_size bytes per message.
The parameter key gives this queue
a "name" so other threads can find it.
The thread calling create
is marked as the "Creator of the queue"
and has the privilege to deallocate the queue and its system resources.
For cross check, the maximum size of the expected messages is compared to the setup of this queue.
msg to the message queue.
The size of the message is given in msg_size.
It has to lower or equal the maximum size that was set
when this instance was "bound".
If you give 0 or no value,
the maximum message size is sent.
Can block the calling thread,
until space for the new message is available.
This behavior is controlled by flag:
BMQ_SEND_WAIT: Wait for free space in queue.
BMQ_SEND_NOWAIT: Do not wait but discard message if queue is full.
Example:
if ((que->send(BMQ_SEND_WAIT, &msg)))
{
CCO_error(__FILE__,__LINE__,"Error sending\n");
return(-1);
}
msg.
The maximum size of a message was set
when this instance was "bound".
The return value is the number of bytes received,
or -1 if there was an error.
Can block the calling thread, until a message is available.
This behavior is controlled by flag:
BMQ_GET_WAIT: Wait for a new message
BMQ_GET_NOWAIT: Do not wait,
but signal error if no message available.
Example:
while (1)
{
if (que->get(BMQ_GET_WAIT, msg) == -1)
{
CCO_error(__FILE__,__LINE__,
"Can`t read from queue %d!\n", 6819);
return(-1);
}
CCO_printf("%s\n", msg);
}
TRUE if this is correct.
TRUE if this is correct.
Header file: `blists.hxx'
The CLEO software group has decided to use STL as their template library of choice. Unfortunately, there is no STL implementation for the real--time operating system running on all our embedded CPU: VxWorks.
To keep the environment of the CLEO Control System still the same on all platforms it is therefore strongly discouraged to use STL in this kind of code. Instead these template lists classes were introduced to BASICS as a (rather weak) substitute.
Our hope is, that at some point in time, we can "revert" to STL everywhere. But for now, we should try to cope with these classes.
Example:
struct Name
{
char* name;
unsigned short prio;
};
// Convenient typedefs
typedef struct Name Name;
typedef BLS_MutexList<Name*> NameList;
class GroupListData
{
public:
GroupListData(const char* name);
virtual ~GroupListData();
const char * groupName() const;
NameList* groupList();
void clearList();
...
private:
...
NameList* myList;
char * myGroup;
};
// A function using the list
void GroupListData::clearList()
{
myList->lock();
if (!myList->isEmpty())
{
// Remove all entries before deleting the list
Name* name;
Name* nxtname;
for (name = myList->getHead(); ; name = nxtname)
{
// Last entry, so just delete
if (myList->isLast(name))
{
// Unregister also!
unregisterOld(name->name);
myList->remove(name);
delete name->name;
delete name;
break;
}
// There is another entry, remember where!
nxtname = myList->getNext(name);
// Unregister also!
unregisterOld(name->name);
// Now, we can delete
myList->remove(name);
delete name->name;
delete name;
}
}
myList->unlock();
}
This example shows the use of a Mutex protected list
(a subclass of the simple list class).
(Using typedef the code becomes much more readable!)
The structure Name is managed with a list
that contains pointers to each instance.
All list classes in BASICS are tailored to use
pointers to instances instead of copies of these.
The "reasoning" behind this approach is,
that lists are only tools to organize objects,
they do not really "manage" the objects.
This is still the job of the programmer!
This approach makes it possible to have the same object in more than one list (e.g. one sorted alphabetically, the other using times). If the object was copied into the list (or container) you would have two distinct instances of the object.
Secondly, all lists are made to contain only distinct items, like numbers or pointers. This makes it possible to "walk through the list" without changing the state of the list, and without keeping an iterator object around. You always deal with the list object directly. Do not add an item twice, it will break the list object!
(Whether this is an advantage or disadvantage is still an open question and depends very much on the view of programmer.)
Base class: virtual public bsobject
A doubly--linked list using the template syntax to be type--safe.
T.
It also names this list.
Since objects are not managed by the list, only the memory for the object pointers are freed. The user is responsible for deleting the objects pointed to!
Do not call this method, if list is empty!
Do not call this method, if list is empty!
t.
Do not call this method, if t is last in the list!
t.
Do not call this method, if t is first in the list!
TRUE if empty, FALSE otherwise.
t.
Returns TRUE if not, FALSE otherwise.
t.
Returns TRUE if not, FALSE otherwise.
Do not insert the same item more than once!
prev.
Do not insert the same item more than once!
follow.
Do not insert the same item more than once!
t from the list.
This does not delete any object
t might point to!
virtual public bsobject
A simple template class implementing a queue of items. You can add new items at the end, and remove items from the top.
T.
It also names this list.
Since objects are not managed by the list, only the memory for the object pointers are freed. The user is responsible for deleting the objects pointed to!
TRUE if empty, FALSE otherwise.
Do not call this method if queue is empty!
virtual public BLS_List<T>
This list has the same behavior as BLS_List,
except that before you call any method,
the list has to be locked by the calling thread.
Failing to do so will result in run--time errors.
T,
and sets the protecting semaphore to "unlocked".
It also names this list.
Since objects are not managed by the list, only the memory for the object pointers are freed. The user is responsible for deleting the objects pointed to!
The return value reflects the success of the call.
The return value reflects the success of the call.
TRUE if yes,
FALSE otherwise.
BSP_Mutex.
virtual public BLS_Queue<T>
This list has the same behavior as BLS_Queue,
except that before you call any method,
the list has to be locked by the calling thread.
Failing to do so will result in run--time errors.
T,
and sets the protecting semaphore to "unlocked".
It also names this list.
Since objects are not managed by the list, only the memory for the object pointers are freed. The user is responsible for deleting the objects pointed to!
The return value reflects the success of the call.
The return value reflects the success of the call.
TRUE if yes,
FALSE otherwise.
BSP_Mutex.
BSP_SBase Construction
This document was generated on 1 May 1998 using the texi2html translator version 1.49.