Saturday, December 1, 2012

What happens if a pthread holding mutex lock exits without unlocking?

This was question asked by someone. It was kind of new to me :-). It was very good question indeed. So what is the answer? Let me write a simple C code.


#include <stdio.h>
#include <pthread.h>

pthread_mutex_t nasty_mutex = PTHREAD_MUTEX_INITIALIZER;

void*
pthread_mutex_function (void *arg)
{
    pthread_mutex_lock(&nasty_mutex);
    printf("Got my lock ;)\n");
    pthread_mutex_unlock(&nasty_mutex);
}

void*
pthread_mutex_nasty_function (void *arg)
{
    pthread_mutex_lock(&nasty_mutex);
}

int main (void)
{
    pthread_t tid[3];
    int i=0;

    pthread_create(&tid[0], NULL, pthread_mutex_nasty_function, NULL);
    pthread_create(&tid[1], NULL, pthread_mutex_function, NULL);
    pthread_create(&tid[2], NULL, pthread_mutex_function, NULL);

    for (; i<3; i++) {
        pthread_join(tid[i], NULL);
    }
}

So what is the output? LOL :D deadlock. This is really nasty coding. I thought LWP state would be cleared even if thread exits however, that is not case. The cleanup happens after process exits not LWP. Conclusion is that we have to make sure nothing crashes when holding lock, that does not mean it should crash after releasing mutex lock ;). For me it was one more learning.

Code tested in Linux mint 14 /64 bit. Validations in code are left to user!

Edit 1: I did mention that thread should not crash while holding a lock. But if the lock is private to process, then entire process address space goes for toss after crash. This will not lead to any deadlocks ;-). However, if thread exits gracefully without releasing lock, then consequences are obvious. I am not sure what happens if the mutex lock is shared across processes and the process holding lock crashes. I will give a try sometimes later when I get time.

Thursday, October 18, 2012

My version of tail program based on inotify

Honestly speaking there is no intention behind the program I did! It is just for learning and time pass.
So how does linux tail program works?

Earlier it was based on sleep and stat. The program used to stat and check the modified time of file.
If file was modified, the difference used to get printed to stdout. Otherwise, it would go for sleep and check back again.

Recently it seems like the tail program in linux has been changed to use inotify system calls (using strace command). Honestly I realized after writing one of mine. I thought I would publish inotify version of mine. But world is gone way ahead and I am late :-). But still it was very good learning for me. I feel the other unix variant use the earlier version of tail since inotify is specific to linux.

So here is the program. It is quite basic and expect more features in future release :-). Test, raise bugs and provide feedback!
https://github.com/nkumar85/tail

Tuesday, July 3, 2012

Programming Gotcha - 2

#include<stdio.h>

int test();

int main()
{
    test(1,2);
}

int test()
{
    printf("Got ya!!\n");
}


So what is the output of the above program?

If you think that, it would result in compilation error then try the program yourself! Yeah.. It does not result in any error. Instead the output is

Got ya!!

So why is it like that? As per C standards, any function declaration with blank arguments can take any number of arguments. It is the common silly mistakes most programmers do including me :-).

How do we get out of such problem? Modify the prototype with explicit void declaration

int test(void);


Now the compiler throws up error!

Thanks for one of the nice tutorial I had in office which exposed this type of mistake. Honestly even I did not knew about it.


Note: The code was compiled using gcc on a 64 bit linux machine

Sunday, June 10, 2012

Programming Gotcha - 1

This is something C programmers do and it is simple mistake. However the mistake can cost you days in debugging. Eventually the mistake turns out to be trivial, however the impact will be huge.

Consider an example cited by my friend:


int main()
{
        uint64_t var = 0;
        var |= (1 << 45);
        printf("%lu\n", var);
}


The above one looks pretty simple right. But there is mistake :-). Where?

Output: 0

Oooooooo... The output is not expected. So what is the problem. See line #4. The constant '1' is treated as 32 bit number by compiler :-). There you go! The shift by left 45 times leads to var being assigned '0' (or invalid number if operation is rotation). You got the point. This can lead to waste of time while debugging. Fortunately gcc warns about this.

warning: left shift count >= width of type [enabled by default]

If you have lot of files, you may even ignore these warnings. It is better to convert these warnings to errors as stated in previous blogs. So how do we correct it? Just typecast!! Since I am using 64 bit machine I have done some ugly ifdef. This can be done in proper way (kindly comment on writing good ifdef or checking for CPU arch). So here is complete program.

#include <stdint.h>
#include <stdio.h>

#define ARCH 64

#ifdef ARCH
        #if ARCH == 64
                #define FORMAT "%lu\n"
        #else
                #define FORMAT "%llu\n"
        #endif
#else
        #define ARCH 32
        #define FORMAT "%lu\n"
#endif

int main()
{
        uint64_t var = 0;
        var |= ((uint64_t)1 << 45);
        printf(FORMAT, var);
}


The output: 35184372088832

You got it right now and no gcc warnings too! As always kindly comment if you have suggestions and improvements.

Thursday, April 19, 2012

Blocking echo on terminal

There may be situation where in you may have to stop echo of characters on console while user types in. For ex: when prompted for password. This can be done very easily by using set of glibc library calls namely tcgetattr and tcsetattr. These library calls internally use ioctl on hardware to achieve the required functionality on terminal. You can achieve with following flow.

1)      Get old terminal configuration using tcgetattr
2)      Mask off echo
3)      Set new configuration to the terminal immediately using tcsetattr and TCSANOW.
4)      Do the work.
5)      Restore the old terminal settings.

Simple is it. So here is the code tested on linux box. Hope you will find it useful. Again I have tried to maintain at-most modularity so that these things can be used as APIs. Code should be portable easily across OSes using glibc.

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <stdint.h>

#define TRUE  1
#define FALSE 0

int term_get_current (struct termios* term)
{
    if (term && !tcgetattr(STDIN_FILENO, term)) {
        return TRUE;
    }

    return FALSE;
}

int term_echo_set (struct termios* term, uint8_t echo_flag)
{
    if (term) {
        term->c_lflag = echo_flag? (term->c_lflag | ECHO):(term->c_lflag & ~ECHO);
        if (!tcsetattr(STDIN_FILENO, TCSANOW, term)) {
            return TRUE;
        }
    }

    return FALSE;
}

int term_restore (struct termios* term)
{
    if (term) {
        if(!tcsetattr(STDIN_FILENO, TCSANOW, term)) {
            return TRUE;
        }
    }

    return FALSE;
}

int main()
{
    struct termios term_old, term_new;
    char buf[50] = {0};

    if (!term_get_current(&term_old)) {
        printf("Unable to get terminal current instance\n");
        goto end;
    }

    term_new = term_old;

    printf("Password Please: ");

    if (!term_echo_set(&term_new, FALSE)) {
        printf("Unable to turn terminal echo off\n");
        goto end;
    }

    scanf("%s", buf);

    /*
     * If turning back echo ON does not succeed, do not exit!
     * Instead proceed to restore old terminal settings
     * In case of failure, do not try to echo the password
     */
    if (!term_echo_set(&term_new, TRUE)) {
        printf("Unable to turn terminal echo on\n");       
    } else {
        printf("\n\nYour password is: %s\n", buf);
    }

    if (!term_restore(&term_old)) {
        printf("Unable to restore old terminal settings\n");
    }

end: return 0;   
}


Compile using gcc. I have not shown output here since it needs to be tried on your own machines.

Off-Topic:

The man pages of tcsetattr has lot of other interesting options to play with terminal. Just have look at man pages.

Please leave comments or suggestions if you have.

Friday, March 30, 2012

Validating link local ipv6 address

I have seen in many places using string comparison to validate link local ipv6 address. However I feel this approach is not ideal and may not fit in all use cases.

For ex in c++ you may write:

string s = "fe80::1234";
s.find("fe80::");

something of this sort. However what if IP address in capitals? The above code will fail.

Ok lets take string library approach

strncasecmp(addr, "fe80:",5) == 0;

This may also work fine. However I feel we can do these things better and right way using standard libraries provided by glibc.

If you need to check for string, use inet_pton() and IN6_IS_ADDR_LINKLOCAL() combination to achieve validation. If you have sockaddr_in6 handy, you only need to use IN6_IS_ADDR_LINKLOCAL(). So here is the program I wrote. I feel modularity is maintained in program to some extent. There are two APIs. One takes string as argument while the other takes sockaddr as argument. In second case, sockaddr in casted to sockaddr_in6 and then validated for link-local ipv6 address.

#include <stdio.h>
#include <netinet/in.h>

typedef _Bool BOOL;

#define B_TRUE  1
#define B_FALSE 0

BOOL is_link_local_ip (const struct sockaddr* sock);
BOOL is_link_local_ip_str (const char* address);

static inline BOOL __is_link_local (struct sockaddr_in6* sock)
{
    return (((IN6_IS_ADDR_LINKLOCAL(&sock->sin6_addr)) == 1)
                    ? B_TRUE : B_FALSE);
}

BOOL is_link_local_ip (const struct sockaddr* sock)
{
    if (sock)
        if (sock->sa_family == AF_INET6) {
            struct sockaddr_in6 *temp =
                    (struct sockaddr_in6*)(sock);
            return __is_link_local (temp);
        }
           

    return B_FALSE;
}

BOOL is_link_local_ip_str (const char *address)
{
    struct sockaddr_in6 __in6_addr;

    if (address)
        if (inet_pton(AF_INET6, address, &(__in6_addr.sin6_addr)))
            return __is_link_local (&__in6_addr);

    return B_FALSE;
}

int main ()
{
    const char* ip_addr = "FE80::224:2CFF:FEA1:8a1";

    if (is_link_local_ip_str(ip_addr))
        printf("Address is ipv6 link_local\n");
    else
        printf("Address is not ipv6 link local\n");
}


So here is the output: Address is ipv6 link_local

You can test program with different test vectors. Apart from link-local, there are lot such macros that come in handy. Please refer: http://uw714doc.sco.com/en/man/html.3N/inet.3N.html

As always leave comment if you have better approach

Wednesday, March 21, 2012

Convert warnings to error with GCC

What happens if you execute below code?

int i = 10;
printf("%s Bad format specifier\n", i);


nandakumar@HERAMBA ~ $ gcc format.c
format.c: In function ‘main’:
format.c:6:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]


Output: Segmentation fault

This is common mistake programmer does. Here printf de-references address location 10 and print out the string value at that address. However 10 is not valid address in the address space and hence the program results in seg fault. GCC also warns about invalid format. However programmers tend to ignore the warnings too often and when errors do happen lot of time is spent to debug the error. The warnings are taken into consideration in above condition since program is too small. However, while working on larger projects, programmers tend to overlook on warnings.

There are two solutions though:

1) Program neatly
2) Find the error during compilation time itself

The first seems to be the ideal solution. However mistakes do happen. The second can be achieved using GCC options. GCC provides compiler switch '-Werror' to convert all warnings to errors. You can even have specific warnings to be shown as errors. For example, in above case we can only use '-Werror=format' to make format warning as error. This greatly helps you to reduce errors even.

How does modified output look like now?

nandakumar@HERAMBA ~ $ gcc -Werror format.c
format.c: In function ‘main’:
format.c:6:2: error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Werror=format]
cc1: all warnings being treated as errors


Now we can see the change! There is an error in program which makes our life easy. That is it for now. Leave comments if you have extra suggestions.

Thursday, March 15, 2012

Thread Safety of 'errno' variable

Everyone knows that each time system call gets execured, the 'errno' will be set 'errno' value of last system call that failed. So it is a good practice to store 'errno' value for further processing if any system call getting called subsequently.

For ex:

socket(...); /* do not worry about args */
printf("Trying to open socket\n");
printf("The errno was = %d\n", errno);


So what is problem with above code? Well, printf is internally write system call. If printf fails, the 'errno' value will reflect the output of printf but not the socket error.

Now consider the example. I create two sockets. One with appletalk stream socket and other arbitrary protocol with datagram socket. We know stream socket is basically for TCP and SCTP based sockets. So the one with SOCK_STREAM gives error and the arbitrary also gives error. See the differences in 'errno'.

socket(AF_APPLETALK, SOCK_STREAM, 0);
socket(200, SOCK_DGRAM, 0);
printf("%d\n", errno);


Output: 97

I modify the code back.

socket(AF_APPLETALK, SOCK_STREAM, 0);
printf("%d\n", errno);
socket(200, SOCK_DGRAM, 0);


Output: 94

You will see difference in 'errno' which confirms our observation. So it is always good practice to store 'errno' you want to catch for particular system call before you proceed further.

Question comes about thread safety. 'errno' is global variable and resides in data segment which means not thread-safe. Does glibc puts any mutex locks around it. Oh thats really horrible thing and if you are using 'errno' directly, it does not make sense even. So how 'errno' is managed? What if 'errno' in one thread is modified by system call return of other thread?

Well glibc does this by making 'errno' per thread variable. For more information on gcc per thread variable see here: http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html

So 'errno' modification is transparent to per thread and not across threads. Hence you can safely assume that 'errno' within a thread is localized and is completely abstracted from other threads. Consider the example:


#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define MAX_THREADS 3

pthread_barrier_t t_barrier;

void* syscall_thread1(void*);
void* syscall_thread2(void*);
void* syscall_thread3(void*);

int main()
{
    pthread_t tid[MAX_THREADS];

    /* It is not required to include main thread. Only for illustration */
    if (pthread_barrier_init(&t_barrier, NULL, MAX_THREADS+1)) {
        printf("Error in initializing pthread barrier\n");
        exit(1);
    }

    if (pthread_create(&tid[0], NULL, syscall_thread1, NULL)) {
        printf("Failed to create thread instance %d\n", 1);
    }
   
    if (pthread_create(&tid[1], NULL, syscall_thread2, NULL)) {
        printf("Failed to create thread instance %d\n", 2);
    }

    if (pthread_create(&tid[2], NULL, syscall_thread3, NULL)) {
        printf("Failed to create thread instance %d\n", 3);
    }

    /*
     * Make sure threads start simultaneously
     * atleast from code point of view,
     * may not be from scheduler point of view
     */
    pthread_barrier_wait(&t_barrier);

    /* Wait for each thread to complete */
    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    pthread_join(tid[2], NULL);

    pthread_barrier_destroy(&t_barrier);

    return 0;
}

void* syscall_thread1(void *instance)
{
    pthread_barrier_wait(&t_barrier);
    printf("In thread = %lu\n", pthread_self());
    if ((socket(AF_APPLETALK, SOCK_STREAM, 0)) == -1)
        perror("socket:");
}

void* syscall_thread2(void *instance)
{
    pthread_barrier_wait(&t_barrier);
    printf("In thread = %lu\n", pthread_self());
    if ((socket(200, SOCK_STREAM, 0)) == -1)
        perror("socket:");
}

void* syscall_thread3(void *instance)
{
    pthread_barrier_wait(&t_barrier);
    printf("In thread = %lu\n", pthread_self());
    if ((open("some_non_existing_file", O_RDWR)) == -1)
        perror("open:");
}


Output:

In thread = 3079547760
socket:: Socket type not supported
In thread = 3071155056
socket:: Address family not supported by protocol
In thread = 3062762352
open:: No such file or directory


Works as expected! However order of print depends on thread scheduling by linux scheduler. We may have to compile glibc with _REENTRANT option to achieve per thread 'errno' storage.


How about digging glibc code for a while?

/usr/include/errno.h says 'errno' is per-thread variable.

#ifdef  _ERRNO_H

/* Declare the `errno' variable, unless it's defined as a macro by
   bits/errno.h.  This is the case in GNU, where it is a per-thread
   variable.  This redeclaration using the macro still works, but it
   will be a function declaration without a prototype and may trigger
   a -Wstrict-prototypes warning.  */

#ifndef errno
extern int errno;
#endif


another snippet under /usr/include/i386-linux-gnu/bits/errno.h

#  if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value.  */
#   define errno (*__errno_location ())
#  endif
# endif /* !__ASSEMBLER__ */
#endif /* _ERRNO_H */


basically errno_location() function gets address of global 'errno' variable. As per the article in here: http://pauillac.inria.fr/~xleroy/linuxthreads/faq.html,

"Thus, for programs not linked with LinuxThreads, defining _REENTRANT makes no difference w.r.t. errno processing. But LinuxThreads redefines __errno_location() to return a location in the thread descriptor reserved for holding the current value of errno for the calling thread. Thus, each thread operates on a different errno location."

which means that each thread gets its own copy of 'errno'.

Small search in cscope for errno_location() leads to hurd/hurd/threadvar.h which says it all. What it means need to dig still further which even I am doing :-). The value seems to be obtained from some offset from thread stack pointer (just assuming).

/* Return the location of the value for the per-thread variable with index
   INDEX used by the thread whose stack pointer is SP.  */

extern unsigned long int *__hurd_threadvar_location_from_sp
  (enum __hurd_threadvar_index __index, void *__sp);
_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index,
                                   void *__sp)
{
  unsigned long int __stack = (unsigned long int) __sp;
  return &((__stack >= __hurd_sigthread_stack_base &&
            __stack < __hurd_sigthread_stack_end)
           ? __hurd_sigthread_variables
           : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) +
                                    __hurd_threadvar_stack_offset))[__index];
}

/* Return the location of the current thread's value for the
   per-thread variable with index INDEX.  */

extern unsigned long int *
__hurd_threadvar_location (enum __hurd_threadvar_index __index) __THROW
     /* This declaration tells the compiler that the value is constant
        given the same argument.  We assume this won't be called twice from
        the same stack frame by different threads.  */
     __attribute__ ((__const__));

_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
__hurd_threadvar_location (enum __hurd_threadvar_index __index)
{
  return __hurd_threadvar_location_from_sp (__index,
                                            __thread_stack_pointer ());
}


Conclusion is glibc marks 'errno' as per thread variable and it is safe to access 'errno' across threads. Any comments or suggestions are greatly welcome

Thanks to wonderful book Linux System Programming by Robert Love through which I came to know that 'errno' is thread safe.

Monday, February 20, 2012

A few minutes of USB Outage


Yesterday one strange problem occurred in my laptop. I booted to vista for weekly backup. I have a Transcend external hard drive as well Seagate. The laptop has only 3 USB ports and I do not have a USB hub. The Transcend drive has two USB cables one for data and one for power. The other port was occupied by mouse. I had to plug out mouse for make room SeaGate hard drive.

As soon as I removed USB mouse, the windows started complaining about USB device malfunction. However SeaGate drive was detected while plugging both Transcend and mouse windows gave repeated errors. I rebooted and again problem was there. I did hard reboot nope again the problem persists. I booted to my xubuntu box, the same problem. ‘dmesg’ showed ‘Unable to enumerate USB device’. I got confused. The boot process took very long time. I was not able to check even bios due to CPU hog (by whom?).

I thought for a while. Hey wait a minute. If none of the OSes are unable to recognize then BIOS firmware ran into problem. I immediately went to download site of DELL and downloaded the BIOS firmware. The BIOS was flashed with the firmware I downloaded. After reboot I inserted the mouse and Transcend external hard drive. Hurrah!! It works. I am still confused why this sort of inconsistency happened with BIOS firmware. Is it the problem with inserting multiple external hard drives at a time? No, this is not possible. I am not hardware expert. Something went wrong with BIOS for sure

Saturday, February 18, 2012

A note on char* initialization

Again it is not something new :). Only thing is that I observed it recently. We can initialize a char* pointer with a constant string even after declaration. The restriction is of-course you cannot modify the content of pointer.

So what is the point. gcc puts the constant strings under read only section of data segment. Consider the example:

int main()
{
        char* str;
        str = "It is me";
        printf("%s\n", str);
}


If you think above code results in segmentation fault, nope. It works fine. So how does output look like

nandakumar@HERAMBA:~$ gcc test.c -o test
nandakumar@HERAMBA:~$ ./test
It is me

So how does gcc manage it. Here is snipped assembly output.

nandakumar@HERAMBA:~$ gcc -S test.c
nandakumar@HERAMBA:~$ head -5 test.s
    .file    "test.c"
    .section    .rodata
.LC0:
    .string    "It is me"
    .text

      
<snip>

You can even do this. It works great

int main()
{
        char* str;
        str = "It is me";
        printf("%s\n", str);
        str = "It is me again :-)";
        printf("%s\n", str);
}


Here is output:

nandakumar@HERAMBA:~$ gcc test.c -o test
nandakumar@HERAMBA:~$ ./test
It is me
It is me again :-)


So the data gets stored in read-only section of text segment and the pointer str points to the location in rodata. In second example you have two entries in rodata section.

nandakumar@HERAMBA:~$ gcc -S test.c
nandakumar@HERAMBA:~$ head -6 test.s
    .file    "test.c"
    .section    .rodata
.LC0:
    .string    "It is me"
.LC1:
    .string    "It is me again :-)"


Can I modify. Not at all. How can you modify rodata :-). It even does make sense the compiler puts it in read only section of text segment since we do not want to mess up with memory. Here is sample

int main()
{
        char* str;
        str = "It is me";
        printf("%s\n", str);
        str = "It is me again :-)";
        printf("%s\n", str);

        str[0] = 'P';
        printf("%s\n", str); /* Get LOST!! */
}


nandakumar@HERAMBA:~$ gcc test.c -o test
nandakumar@HERAMBA:~$ ./test
It is me
It is me again :-)
Segmentation fault


Note that having more constant strings bloats the executable size. Also be careful not to modify the contents. How can you make more precise about rodata? Consider this case

int main()
{
        char* str;
        str = "It is me";
        printf("str address is %p and content \"%s\"\n", str, str);
}


The output:

nandakumar@HERAMBA:~$ gcc test.c -o test
nandakumar@HERAMBA:~$ ./test
str address is 0x80484f0 and content "It is me"

The snipped version of objdump

nandakumar@HERAMBA:~$ objdump -D test

<snip>

Disassembly of section .rodata:

080484e8 <_fp_hw>:
 80484e8:    03 00                    add    (%eax),%eax
    ...

080484ec <_IO_stdin_used>:
 80484ec:    01 00                    add    %eax,(%eax)
 80484ee:    02 00                    add    (%eax),%al
 80484f0:    49                       dec    %ecx
 80484f1:    74 20                    je     8048513 <_IO_stdin_used+0x27>
 80484f3:    69 73 20 6d 65 00 25     imul   $0x2500656d,0x20(%ebx),%esi
 80484fa:    70 2d                    jo     8048529 <_IO_stdin_used+0x3d>
 80484fc:    25                       .byte 0x25
 80484fd:    73 0a                    jae    8048509 <_IO_stdin_used+0x1d>
    ... 


<snip>

The virtual memory location 0x80484f0 points to "It is me" (ignore the disassembled output). Note that the VM address may change every time you run.

That is it. I know you are feeling such silly thing but new for me. Leave your suggestions too!

Note:
1) Skipped C headers in code.
2) All codes were tested in Linux box and gcc compiler.
3) You can even run Valgrind to check sanity of code.

Small Correction: Earlier it was mentioned as read only data segment, however it is read only section of text segment. My apologies for mistake :-). Corrections are made at appropriate locations of write-up.

Saturday, January 28, 2012

My ISP finally happy with Ubuntu box


I was struggling to make my Ubuntu box work with login server of ISP. It was not getting better at all. Sometimes after 50 attempts, ISP used to say yes and login window appeared. However I was totally annoyed by this. When I switch back to Windows, everything was fine. I started digging to the problem myself rather than asking ISP itself (just for fun and learning).

1)      ISP provides a cable modem and recognizes the packets by MAC address of cable modem.
2)      I have a wireless router attached to my laptop.
3)      The WAN cable of modem is connected to wireless router.
4)      All my connections go via wireless router to cable modem to ISP Internet gateway.
5)      Wireless router has DHCP server to provide IP address to locally connected hosts.
6)      Of-course it acts like a NAT and router, in the sense you can have multiple hosts connecting to wireless router (not sure about limit).

The network setup is something like this:

NETWORK-SETUP
Let me come back to the problem of login server not responding. I struggled a lot. I thought the problem with wireless router and ISP may not be accepting the MAC other than my PC. No I was wrong, in windows everything was clean. Next, I pulled out wireless router and directly cabled modem to my PC. Again did not work out. I used to login from windows and work with Ubuntu for my net access. This was successful since login information was maintained in ISP side than locally in the system.

After so much of struggle, I decided to take packet captures of both windows and Ubuntu. I observed Ethernet packets and IP packets and they looked similar. Finally I gazed through TCP packets.

Aha here you are! Linux adds all TCP options to TCP packet while windows adds few. I knew this was problem but which options? I started disabling one by one

sudo sysctl net.ipv4.tcp_sack=0

This did not work

sudo sysctl net.ipv4.tcp_window_scaling=0

Na this did not work. I thought my assumption was wrong. I decided to give final try

sudo sysctl net.ipv4.tcp_timestamps=0

Hurrah!!! It worked out. I was really delighted. I updated the /etc/sysctl.conf and never faced the problem again.

So it is basically problem with tcp timestamp option which linux kernel includes by default. I really did not understand why this would give a problem. TCP timestamp just sends current clock of the system to avoid packets being recognized as duplicate during sequence number overflow. However they need not even synchronize with system clock. I raised this issue with ISP and let me see what happens further.

At the end of day, one more piece of learning and one more topic to write about ;). I just loved the investigations I carried out. It may be very silly problem to experts however for me it was seamless learning.

Here is the TCP packet capture of windows and linux. It shows Windows does not add TCP timestamp field in TCP packet during SYN state.



Courtesy: wireshark

Tuesday, January 24, 2012

A simple player simulation using pthreads

When I was playing VLC, just wondering how pause, play and resume works. I decided to simulate one using pthreads. This is just done for fun nothing official. So I used the wait and resume calls of pthreads.

1) pthread_cond_wait()
2) pthread_cond_signal()

Using above two POSIX calls I did a simulation of player pause and resume. It worked as expected. So it was done as below

1) Player is executed as a separate thread
2) Button simulation done using command line in main thread.
3) When pause is opted, pthread_cond_wait() is called to make thread wait.
4) When resume is opted, pthread_cond_signal() is called to wake up the waiting thread.

As far as wake up is concerned, there is one more variant pthread_cond_broadcast() which wakes up all threads waiting on condition variable. Please refer man pages to know detailed usage of pthread calls. Not sure about internals may be the futex is released atomically and wakeup** is called for this task (again not sure)

Here is C code, not completely tested however giving what is required. Suggestions and further improvements are always welcome.

#include<stdio.h>
#include<unistd.h>
#include<termios.h>
#include<stdlib.h>
#include<pthread.h>

typedef enum {
    PLAY,
    PAUSE,
    STOP,
}player_state;

struct player {
    pthread_mutex_t player_mutex;
    pthread_cond_t player_cond;
    pthread_t player_tid;
    player_state player_s;
};

static void init_player(struct player *__arg);
static void print_player_menu(void);
static int start_player(struct player *__arg);
static int pause_player(struct player *__arg);
static int resume_player(struct player * __arg, const player_state player_s);
static int stop_player(struct player *__arg);
static char read_char(void);
void* start_player_thread(void *__arg);

int main()
{
    struct player bazooka_player;
    init_player(&bazooka_player);
    print_player_menu();

    while (1) {
        char c = read_char();

        switch (c) {
            case 'S':
            case 's':
                if (bazooka_player.player_s == STOP) {
                    start_player(&bazooka_player);
                } else {
                    printf("Invalid State to call player start\n");
                }
                break;

            case 'P':
            case 'p':
                if (bazooka_player.player_s == PLAY) {
                    pause_player(&bazooka_player);
                } else {
                    printf("Invalid State to call player pause\n");
                }
                break;

            case 'R':
            case 'r':
                if (bazooka_player.player_s == PAUSE) {
                    resume_player(&bazooka_player, PLAY);
                } else {
                    printf("Invalid State to call player resume\n");
                }
                break;

            case 'Q':
            case 'q':
                stop_player(&bazooka_player);
                exit(EXIT_SUCCESS); //Any better way?
                break;

            default:
                printf("Invalid player option\n");
                break;
        }
    }
}

static void init_player(struct player *__arg)
{
    /*
     * Make sure you do proper initialization
     * Otherwise pthread_cond_signal() would result in deadlock
     */
    __arg->player_s = STOP;
    __arg->player_tid = -1;
    pthread_cond_init(&__arg->player_cond, NULL);
    pthread_mutex_init(&__arg->player_mutex, NULL);
}

static char read_char(void)
{
    /*
     * This is taken from net.
     * It basically turns of echo for the current terminal.
     * Takes single character without expecting new line.
     * Restores old tty settings.
     * returns character.
     */
    char c;
    struct termios old_term, new_term;
    tcgetattr(STDIN_FILENO, &old_term);
    new_term = old_term;
    new_term.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
    c = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
    return c;
}

static void print_player_menu(void)
{
    printf("PLAYER OPTIONS\n");
    printf("S or s: Start play\n");
    printf("P or p: Pause play\n");
    printf("R or r: Resume play\n");
    printf("Q or q: Stop play\n");
}

static int start_player(struct player *__arg)
{
    /*
     * This could get racy if we set state to PLAY after pthread_create().
     * Do we need explicit memory barrier in multi-core platform?
     * smp_wmb()? Not sure :-)
     */
    __arg->player_s = PLAY;
    return pthread_create(&__arg->player_tid, NULL, start_player_thread, __arg);
}

static int pause_player(struct player *__arg)
{
    __arg->player_s = PAUSE;
}

static int resume_player(struct player *__arg, const player_state player_s)
{
    printf("Preparing to resume\n");
    __arg->player_s = player_s;
    /*
     * Again Do we need smp_wmb()?
     */
    return pthread_cond_signal(&__arg->player_cond);
}

static int stop_player(struct player *__arg)
{
    /*
     * This may hang the thread if the player is paused.
     * We will have to explicitly do signal in case, player is paused
    */

    if (__arg->player_s == PAUSE) {
        resume_player(__arg, STOP);
    } else {
        __arg->player_s = STOP;
    }

    return ((__arg->player_tid == -1)?0:pthread_join(__arg->player_tid, NULL));
}

void* start_player_thread(void* __arg)
{
    struct player* pl_s = (struct player*) __arg;
    while (1) {
        switch (pl_s->player_s) {
            case PLAY:
                printf("playing the song :-)\n");
                sleep(1); //Not sure how much safe to call this inside a thread
            break;

            case PAUSE:
                printf("preparing to pause :-)\n");
                pthread_mutex_lock(&pl_s->player_mutex);
                pthread_cond_wait(&pl_s->player_cond, &pl_s->player_mutex);
                pthread_mutex_unlock(&pl_s->player_mutex);
            break;

            case STOP:
                printf("good bye! Hope you enjoyed it :-)\n");
                pthread_exit(NULL);
            break;   
        }
    }
}


Compile with: gcc -o <binary_name> <saved_c_file> -lpthread
Execute with: ./<binary_name> and test output

Monday, January 16, 2012

The VirtualBox 4.1.8

The new version of virtual box seems to have improvements on the native graphic resolution. My guest OS screen now fits into entire screen of host OS rather than it was limited to a specific area in earlier versions. This was happening even if  guest add-ons were installed. The problem seems to have gone by now. Now I am getting real feeling of linux box on vista without installation of guest additions. I recently installed OpenSUSE 12.1 32 bit edition with XFCE desktop as guest on top of Vista and looks magnificent. Here are some screen shots

FULL SCREEN OPENSUSE 12.1

OPENSUSE 12.1 ON WINDOWS VISTA
That really looks nice. Of-course this was only for experiment. Personally I use linux installed onto the hardware system :-).