Following test is done with "Ubuntu EGLIBC 2.12.1-0ubuntu9"

Based on my simple test, 'select' function is poor to validate file descriptor.
In my test, select doesn't return error (-1) even for file descriptor 99999. Some times process is crashed - segment fault.
So, file descriptor should be validated before calling 'select'.
(I think I need to look into more about this. These are based on just test. So I'm not 100% sure about this.)

There is lot's of way. Here is well-known way.

is_valid_fd(int fd) { fcntl(fd, F_GETFL) != -1 || errno != EBADF; }

Summay. Be careful using 'select'!

'Language > C&C++' 카테고리의 다른 글

[C/C++][Linux] Tips about LD_PRELOAD  (0) 2010.12.13
[C/C++][linux] redirect standard io with pipe in code.  (0) 2010.12.10
[C/C++] Encapsulation tip in C.  (0) 2010.11.12
[C/C++] Tips and Memos  (0) 2010.11.12
[C/C++] Getting return address…  (0) 2010.11.03

Usually, pointer of not-opened-structure is used to hide module's information.
C dummies may use 'void*' to do this. But, it's not good way.
Let's see following example.
(Following codes are test in GCC4.4 with '-Wall' option.

typedef void module_t;             /* <-- *1 */
typedef struct _sModule module_t;  /* <-- *2 */

module_t* create_module(int arg);
int       do_something(module_t* m, int arg);
...
do_something((int*)m, 1); /* <-- *a */

Pointer of any type can be casted to 'void*', and 'void*' can be casted to pointer of any type without warning.
So, in case of (*1), (*a) doesn't generate any warning. That is, it is NOT TYPE SAFE (in compile time).
But, in case of (*2), GCC give warning like "... incompatible pointer type ...". It's TYPE SAFE.
And, interestingly, compiler doesn't complain anything about (*2) because, compiler doesn't need to know size of 'struct _sModule'.
Only pointer is used. So, knowing size of pointer type is enough and compiler already know it.
So, in terms of syntax, it's ok too!

Boolean to integer - C.

Let's think about the function that return 0 if false, otherwise 1.

 => Naive way : return (e)? 1: 0;

C doesn't support boolean type. Instead, 0 is false, non 0 is true in C.
There is no fixed value to represent TRUE.
But, as defined by 4.5/4, boolean true is promoted to 1, boolean false to 0.
So, we can improve this to

 => Better way : return !!(e);

And this way is also useful because we can get fixed integer value - integer 1 - for TRUE boolean value.

* The ORDER that function PARAMETERS are EVALUATED, is NOT SPECIFIED.
The only requirement is "Those should be fully evaluated before function is called."

Very simple... Just describing here for me to remind.

=== ARM(32bit) - RVCT ===
/* #pragma O0 <- due to optimized out, this may be required */
{ /* Just Scope */
    void* ra;
    /* register lr(r14) has return address */
    __asm
    { mov ra, lr }
    /* now variable 'ra' has return address */
}

=== x86(32bit) - GCC ===
{ /* Just Scope */
    register void* ra; /* return address */
    /* return address is stored at 4byte above from 'ebp' */
    asm ("movl 4(%%ebp), %0;"
         :"=r"(ra));
    /* now variable 'ra' has return address */
}

'Language > C&C++' 카테고리의 다른 글

[C/C++] Encapsulation tip in C.  (0) 2010.11.12
[C/C++] Tips and Memos  (0) 2010.11.12
[Linux][C/C++] Understanding Signals – User Signal Handler  (0) 2010.10.29
[C/C++] type of hard-coded-string.  (0) 2010.09.16
[C/C++] Function pointer.  (0) 2010.05.24

Signal is used for interaction between User Mode processes(henceforth UMP) and for kernel to notify processes of system events.
There are lots of materials you can find to understand what Signal is. So, let's skip it.
The point of this article is "How user signal handler(henceforth USH) is executed?" in Linux.

The core what Linux Kernel does to deliver signal, is modifying stack of UMP - usually adding data.
This is very important! UMP's stack itself is changed!
Kernel changes UMP' stack and register values as if  USH is called from specific function - let's call it F.
(For example, PC is set to USH. Return address in stack is set to function F.)
And, usually, F is just system call - sigreturn. At this system call, Kernel back UMP's stack to original values.
Here is simplified flow.

Signal is issued --> Kernel changes UMP's stack -> USH is executed -> return to function F -> System call (sigreturn) -> UMP's stack is restored -> UMP is executed in normal.

In case of multi-threaded process, thread stack is changed. Nothing different.
Understood? Than what is point?
Yes, USH is run at issued process's / thread's context in User Mode.
Let's see following codes.

/* Timer is used for example */
static pthread_mutex_t _m;
...
static void
_signal_handler(int sig, siginfo_t* si, void* uc) {
    pthread_mutex_lock(&_m);
    ...
    pthread_mutex_unlock(&_m);
}

int main(...) {
    ... /* signal is requested (ex timer) somewhere here */
    pthread_mutex_lock(&_m);
    ... /* <--- *a */
    pthread_mutex_unlock(&_m);
    ...
    return 0;
}

Can you image what I am going to talk about?
As I mentioned above signal handler is run in issued thread's context. So, if signal is issued at (*a), program is stuck due to deadlock!
So, signal handler of above codes should be like follows

static void*
_signal_handler_thread(void* arg) {
    pthread_mutex_lock(&_m);
    ...
    pthread_mutex_unlock(&_m);
}

static void
_signal_handler(int sig, siginfo_t* si, void* uc) {
    pthread_t thd;
    pthread_create(&thd, NULL, &_signal_handler_thread, NULL);
}

Done!

'Language > C&C++' 카테고리의 다른 글

[C/C++] Tips and Memos  (0) 2010.11.12
[C/C++] Getting return address…  (0) 2010.11.03
[C/C++] type of hard-coded-string.  (0) 2010.09.16
[C/C++] Function pointer.  (0) 2010.05.24
[C/C++] Memory(Heap) alloc/free interface for the library.  (0) 2010.04.20

Here is example.

sizeof("12345") == 6

What this meas? Type of hard-coded-string (like "12345") is char[].
It's important and interesting! I haven't known this for several years! Hmm...

This is example for using function pointer in C. (basically, C++ case can be easily inferred from C's one)

Syntax related with function pointer type is quite different from other normal(?) one.
So, here is summary.

* type definition
typedef void (*<type name>) (int, void*);

* variable definition
void* (*<var name>) (int, void*) = NULL;
=> define function pointer variable that's type is "void*(*)(int, void*)" and initialize it into 'NULL'.

* type casting.
fpointer1 = (void*(*)(int, void*)) fpointer2;
=> cast function pointer 'fpointer2' into "void(*)(int,void*)" type.

* function that returns function pointer - float(*)(float, float).
=> float (*get_ptr(char c))(float, float); <- parameter is "char c", return type is "float(*)(float, float)"

* function - returns function pointer - pointer variable .
=> void(*(*var_name)(char c)) (void*); <- return function pointer type is "void(*)(void*)", parameter is "char c" and variable name is 'var_name'

* declare function pointer variable whose return type is function pointer.
=> int(* (*get_func)(int))(int, int); <- parameter of function is "int" And it returns function pointer "int(*)(int,int)"

* typecasting to function pointer whose return type is function pointer.
=> int(*(*)(int))(int, int); <- pointed function's return type is "int(*)(int,int)&quot;.

* array of function pointer.
=> static int(*array_name[])(float) = { ... }; <- "int(*)(float)" typed function pointer array.

* pointer of function pointer
=> void*(**<var name>)(int, void*); <- <var name> is pointer of function pointer. it's type is "void*(**)(int, void*)"

Let's narrow the subject down to the 'C' case.

In case of implementing reusable library, sometimes we want to add some hidden information at the allocated memory used in the library. To achieve this, library may support special paired-interface. For example

    void* mylib_malloc(unsigned int size);
    void mylib_free(void* p);

To simplify discussion, let's assume that we want add just hidden 'int' value.
We can easily think two options.
- add hidden value to the end of allocated memory. -- (*1)
- add to the start of it. -- (*2)

But we cannot use (*1), because, in general, we cannot know size of memory that is allocated. Therefore there is no general way to access hidden value by address.
So, (*2) is only way we can use. Actually, this is general way to implement standard 'malloc' function, too.

then, memory block structure will be like this.

            returned value
             of 'mylib_malloc'
                 |
                 v
    +------------+-------------------
    | hidden-int | user-allocated
    +------------+-------------------

We should keep in mind these.
- Size of hidden value depends on data-align-constraint. That is, memory address of user-allocated-space should obey data-align-constraint. For example, in case of 32bit ARM, 4 byte data align is required. So, size of hidden value should be multiple of 4 to get 4-byte-aligned-address for user space.
- 'mylib_alloc/mylib_free' should make a pair. (Standard-free-function should not be used - it raises error.)

"Signal and Slot" concept in QT is very impressive. So, I mimicked it. Here is my mimicked version sample.
(I know... This is humble... But, it has been useful for me..)

typedef struct {
  void*   obj;
  void*   func;
}___yZw_yzW_FiT___;
...
typedef void (*___yZw_yzW_FuncT1___) (void*, void*);
...
#define SLOT1_TYPE  ___yZw_yzW_FuncT1___
...
#define DEF_SLOT1(cLASS, sLOT, tYPE1) \
void  sLOT (tYPE1); \
static void ___##sLOT##_yZw_s___( void* ___yZw_t___,  \
                                  void* ___yZw_d1___) {\
  ASSERT( ___yZw_t___ && ___yZw_d1___ ); \
  tYPE1 a1;\
  memcpy(&a1, ___yZw_d1___, sizeof(tYPE1)); \
  ((cLASS*)___yZw_t___)->sLOT(a1); \
}
...
#define DEF_SIGNAL1(cLASS, sIGNAL, tYPE1) \
CArr<___yZw_yzW_FiT___>    ___yZw_##sIGNAL##_a___;\
void sIGNAL (tYPE1 ___yZw_a1) const { \
  for(int i=0; i<___yZw_##sIGNAL##_a___.Size(); i++) {\
    (*((___yZw_yzW_FuncT1___)(___yZw_##sIGNAL##_a___[i].func)))(___yZw_##sIGNAL##_a___[i].obj, \
                                                                (void*)&___yZw_a1 ); \
  }\
}
...
// argument [sIG_CLASS] is reserved for future use.
#define CONNECT(sIG_CLASS, sIG_OBJ, sIGNAL, sLOT_CLASS, sLOT_OBJ, sLOT) \
do{\
  int __yZw_i__; \
  for(__yZw_i__=0; __yZw_i__<(sIG_OBJ)->___yZw_##sIGNAL##_a___.Size(); __yZw_i__++){ \
    if( ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].obj == (void*)(sLOT_OBJ)) && \
      ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].func == (void*)&sLOT_CLASS::___##sLOT##_yZw_s___) ){ break; } \
  } \
\
  if(__yZw_i__ >= (sIG_OBJ)->___yZw_##sIGNAL##_a___.Size() ) \
  { /* Not in the list */ \
    ___yZw_yzW_FiT___   _info; \
    _info.obj = (void*)(sLOT_OBJ); \
    _info.func = (void*)(&sLOT_CLASS::___##sLOT##_yZw_s___); \
    ((sIG_OBJ)->___yZw_##sIGNAL##_a___).Append(_info); \
  } \
  else {;/* do nothing - duplicated slot is not allowed */ } \
}while(0);

// argument [sIG_CLASS] is reserved for future use.
#define DISCONNECT(sIG_CLASS, sIG_OBJ, sIGNAL, sLOT_CLASS, sLOT_OBJ, sLOT) \
do{ \
  int __yZw_i__; \
  for(__yZw_i__=0; __yZw_i__<(sIG_OBJ)->___yZw_##sIGNAL##_a___.Size(); __yZw_i__++){ \
    if( ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].obj == (sLOT_OBJ)) && \
      ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].func == &sLOT_CLASS::___##sLOT##_yZw_s___) ){ break; } \
  } \
  if( __yZw_i__<(sIG_OBJ)->___yZw_##sIGNAL##_a___.Size() ) { ((sIG_OBJ)->___yZw_##sIGNAL##_a___).Remove(__yZw_i__); } \
}while(0);
...

Here is example code to use this.

// Class definition
class CObj1
{
public:
  CObj1(void){
    _a = 0; _b = 0;
  }

  // virtual DEF_SLOT overriding.
  void  Name(char*);

  // DEF_SLOT functions.
  DEF_SLOT1(CObj1, Set_A,
            int);
  DEF_SLOT1(CObj1, Set_B,
            int);

  // DEF_SIGNAL functions.
  DEF_SIGNAL1(CObj1, Put_A,
              int);
  DEF_SIGNAL1(CObj1, Put_B,
              int);

private:
  int   _a;
  int   _b;
};
...

// Main code

int main() {
  CObj1 o1_1;
  CObj1 o1_2;

  o1_1.Set_A(1);
  o1_1.Set_B(2);

  CONNECT(CObj1, &o1_1, Put_A,    // Signal
          CObj1, &o1_2, Set_B );  // Slot
  CONNECT(CObj1, &o1_1, Put_A,    // Signal
          CObj1, &o1_2, Set_A);   // Slot
  ...
}
[[ blog 이사 과정에서 정확한 posting날짜가 분실됨. 년도와 분기 정도는 맞지 않을까? ]]

Java has useful visibility; package private.
Let's see the following case.

We want implement quite big module A. And this has some sub features. So, we need to make sub classes a, b, c.

In this case, external module should be able to see only interfaces of A; Not those of a, b and c. It is very difficult to make this in C++. But, in java, we can use package private. Here is design example.

Put all these modules in the same package.
Make interfaces of A as public.
Make all interfaces of a, b and c be package private.

Developer can easily know that using a, b and c directly is not allowed intuitively.

How about in C++?
In C++, there is no proper way to do this. Making A be 'friend' of a, b and c, breaks encapsulation. Making interfaces of a, b and c be public, may lead to misuse of those; we want only interfaces of A be visible to external.

I has been desired this kind of visibility - ex. namespace private - when using C++. :-)

+ Recent posts