Saturday, December 14, 2013

Message Buffer vs Data Queue: Refer status

① Difference between referring Message Buffer and Data Queue

ref_mbf() returns the task id for waiting receive and send tasks, number of messages in the buffer and size of free message buffer area.
ref_dtq() returns the task id for waiting receive and send tasks and number of data elements in the data queue.

② ITRON implementation of referring message buffer
ER ref_mbf(ID mbfid, T_RMBF *pk_rmbf)
{
        Sanity check on arguments;
        enter critical section;
        parse through the buffer byte-by-byte by checking the boundary to check number of valid messages and
                store it in pk_rmbf->smsgcnt;
        store the free buffer size in pk_rmbf->pk_rmbf
        check the receive waiting task queue;
        if (any task exists) {
                store the task id into the pk_rmbf->stskid;
        }
        else {
                pk_rmbf->stskid = TSK_NONE;
        }
        check the send waiting task queue;
        if (any task exists) {
                store the task id into the pk_rmbf->rtsk_d;
        }
        else {
                pk_rmbf->rtsk_d = TSK_NONE;
        }
        exit critical section;
        return E_OK;
}
 

Message Buffer vs Data Queue: Deletion

① Difference between deletion of Data Queue and Mailbox

Both processings are almost same.

② ITRON implementation of deleting Message Buffer

ER del_mbf(ID mbfid)
{
        If (called from ISR)
                return E_CTX;
        Sanity check on arguments;
        enter critical section;
        for (each task waiting in the send-wait and receive-wait queue) {
                Get the task control block from the task ID
                Assign E_DLT in the return error code of the task's context;
                if task is waiting in Timeout
                        remove from timer queue
                Set task status as Ready
                if the task is NOT suspended {
                        Change the task to the Ready Queue of priority
                        If (the task priority is higher than the current)
                                set the flag to call scheduler
                } else {
                        Just delete the task from the send wait queue
                }
        }
        Free all the memory allocated for the data queue;
        if (the flag to call scheduler is set) {
                call scheduler;
        } else {
                exit critical section and return E_OK;
        }
}

Message Buffer Vs Data Queue: Receive message

① Implementation difference between Message buffer receive and Data queue Receive

Data queue is based on single data element reception. So, when some sending tasks are waiting, at the end of this function, just one taks at the head of the send-waiting queue is allowed to use the space to store the data. But, Message Buffer is based on variable length messages. So, when using the emptied space, all the tasks till the send-wait queue is emptied or the placing of the message fails is carried out.
 
Remember this API returns the message length received. No other APIs except Send Message buffer, Receive Message Buffer and some APIs in rendezvous returns a non-zero data in between scheduling (as a blocking call).

cre_xxx returns the Non-zero value, but it never blocks. Zero message length and messages with more length of the buffer are nothing to do with this system call. Because, when these are found in snd_mbf, error is returned.

② ITRON implementation of receiving message buffer

ER rcv_mbf(ID mbfid, VP msg)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        /* First check about the buffer empty condition */
        if (buffer is empty == 0) {
                /* If free, check send task queue for synchronous message passing */
                Check send task waiting queue;
                if (some send task is waiting) {
                        /* Copy the message to the send task's buffer */
                        Get the size of message from task's context and if not zero {
                                Get the pointer to message from task's context and copy the message from;
                        }
                        /* Wakeup procedure for send tasks */
                         if task is waiting in Timeout
                                 remove from timer queue
                         Set task status as Ready
                         if the task is NOT suspended {
                                 Change the task to the Ready Queue of priority
                                 If (the task priority is higher than the current){
                                         call scheduler
                                         /* Execution will return here */
                                         return the message size
                                 } else {
                                         Exit critical section and return message size
                                 }
                         } else {
                                 Just delete the task from the send wait queue
                                 Exit critical section and return message size
                         }
                }
                /* No waiting send tasks. This function needs to aquire the message buffer from
                    the buffer. But, the buffer is empty. So, this function needs to wait. */
                /* No data, no sending task, so got to waiting */
                If (polling mode)
                        Exit critical section and return E_TMOUT;
                If (this function is called from interrupt context) or
                If (called from task independent state ex: timer handlers) or
                If (called from dispatch disabled state)
                        Return E_CTX;
                If (Timeout value is specified) {
                        Add task into timer queue;
                        Set TCB flags that 'Waiting in message buffer receive wait queue, Check for Timeout'
                } else (Wait forever) {
                        Set TCB flags that 'Waiting forever in message buffer receive wait queue'
                }
                Set data queue ID in TCB
                Store the buffer pointer in context
                Change the task from ReadyQueue to the Data queue's receive wait Queue
                Schedule the tasks, since this task is going to sleep
                (Once the task is released, execution will return here)
                Return the value set by scheduler(Scheduler directly set return value before return here)
                /* When this task is waken up, the message size will be set in error code register */
        }
        /* Some data is in the message buffer. Just receive it */
        If (maximum message size is 1) {
                Just copy single bytes. /* There is
                any other management data is not needed inside the buffer. */
                Read the data and place on this function's message buffer;
                Increment the free buffer size;
                Adjust the read pointer;
                Remember the length;
        } else {
                Read length byte by byte
                Increment the free buffer size
                Copy the message by taking consideration of that it might have been wrapped.
                Remember the size;
        }
        /* check for send tasks waiting for to get free space in queue */
        /* check for some free space in buffer. Now, the sending tasks needs to be
           checked to push the data into the buffer */
        Check send task waiting queue;
        for (every send task that is waiting in each priority level) {
                take the message size from the task's context;
                take the message data from the task's context;
                if (discovered zero length message size) {
                        break;
                } else {
                        Try to copy the message into the buffer;
                        if (copy failed)
                                break;
                }
                /* Data is placed in the buffer. So, wakeup processing. */
                if task is waiting in Timeout
                         remove from timer queue
                Set task status as Ready
                if the task is NOT suspended {
                        Change the task to the Ready Queue of priority
                        If (the task priority is higher than the current){
                                set flag that scheduler needs to be called
                        }                        }
                } else {
                        Just delete the task from the send wait queue
                }
        }
        if (flag is set) {
                call scheduler
                return the remembered length;
        }
        Exit critical section and return the remembered length;
}
 

Message Buffer Vs Data Queue: Send Message


① Implementation difference between Send Data Queue and Send Message Buffer

Message buffer has one more parameter to save that is message length. Similarly, in synchronous message passing the length needs to be passed to the contexts error code so that it would be returned in the rcv_mbf();

② ITRON implementation of sending message buffer

ER snd_mbf(ID mbfid, VP msg, UINT msgsz)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        /* Check any Rx task is waiting. Can copy message directly (synchronous message passing) */
        Check head of receive wait queue
        If there is valid task id {
                Get the pointer to store data from task's context and copy the message;
                Get the register for return error code and store the size of the message in it;
                if task is waiting in Timeout
                        remove from timer queue
                Set task status as Ready
                if the task is NOT suspended {
                        Change the task to the Ready Queue of priority
                        If (the task priority is higher than the current){
                                call scheduler
                                return error code from scheduler
                        } else {
                                Exit critical section and return error code from it (E_OK)
                                (return E_OK)
                        }
                } else {
                        Just delete the task from the receive wait queue
                        Exit critical section and return the error code from it (E_OK)
                        (return E_OK)
                }
        }
        /* No Rx task is waiting here */
        /* if have valid data length, need to put over the buffer */
        If (have valid message size to send) {
                Check sending wait queue for any waiting task at head of each priority level
                if (No send task is waiting) {
                        /* No sending task; so put the message in the buffer */
                        /* if you could put successfully, then return. Otherwise, wait go and wait */
                        /* Try to put the message in the buffer as follows */
                        Just separate the count as signle and multiple
                        /* Because, if maximum message size is 1, then it will be very much
                        similar to the Data Queue. No separate count mechanism inside the buffer is needed */
                        If free size is 0, then set message copying = Failure;
                        Decrement the free count
                        Place the data
                        Update the put pointer
                        /* Otherwise extra data of two bytes are needed just to remeber the number of valid bytes placed on the buffer */
                        Reduce the free buffer count;
                        Put each and each byte of the length by checking the boundary of the buffer and wrapping.
                        Place the data with consideration of Wrapping the buffer out
                        message copying = Success;
                        If (message is copied successfully) {
                                Exit critical section and return the error code from it (E_OK)
                                return E_OK;
                        }
                        /* Otherwise go down for waiting. If message is longer than buffer, all calls may wait */
                }
                /* Some task is already waiting. You also need to wait */
                If (polling mode)
                        Exit critical section and return E_TMOUT;
                If (this function is called from interrupt context) or
                If (called from task independent state ex: timer handlers) or
                If (called from dispatch disabled state)
                        Return E_CTX;
                If (Timeout value is specified) {
                        Add task into timer queue;
                        Set TCB flags that 'Waiting for send message buffer, Check for Timeout'
                } else (Wait forever) {
                        Set TCB flags that 'Waiting forever for send message buffer'
                }
                Set data queue ID in TCB
                Store the message pointer in context
                Store the message size in context
                Select Queue according to queueing order
                If (Tasks should be granted in FIFO order)
                        Select send wait queue->Queue[0] as Queue
                Else (Should be granted in Priority order)
                        Select send wait queue->Queue[Current Tasks Priority]
                Change the task from ReadyQueue to the Data queue's send wait Queue
                Schedule the tasks, since this task is going to sleep
                (Once the task is released, execution will return here)
                Return the value set by scheduler(Scheduler directly set return value before return here)
        }
        Exit critical section and return the error code from it (E_OK)
        return E_OK;
}
 

Message buffer vs Mail box: Creation

① Difference between Message buffer and Mailbox
 
Mail box:
 
You have your own suitcase with a handle. You dump your things in that and pass it to us. We will use the handle to put it again in the roller.
 
"Mailbox suitcase"
 
Message Buffer:
 
Just give your message! We have space to share it.
 
"Message buffer notice board"
 
A message buffer transfers a variable-sized message through copying. It is different from a data queue in that it transfers variable-sized messages. It is different from a mailbox in that it copies the messages. A message buffer is assumed to be implemented as a ring buffer.
 
Message buffer is exactly same as data queue with Send & Receive wait queues, Prioritized sending, FIFO Receive, Ring buffer, data copy, synchronous message passing. Differencea are variable sized data unit which may need additional management data in the ring buffer and forced send is not there.
 
② ITRON implementation of cre_mbf
 
ER cre_mbf(ID mbfid, T_CMBF *pk_cmbf)
{
        Check context. If called from ISR,
                return E_CTX;
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Allocate memory for the data queue and send task queue;
        (for data queue, each element is sizeof(void pointer))
        Initialize the data queue structure;(data queue structure is as follows)

        In this function, start, head, tail parameters are initialized to start address
        end parameter is initialized to end address
        Counter for number of valid data elements is initialized to zero
        Initialize the receiving task waiting queue structure;(Only FIFO order. so,)
                Initialize queue as follows:
                ┏━━━━━┯━━━━━━┓
                ┃Queue   │Queue     ┃
                ┃[0]     │Tail       ┃
                ┗━━━━━┷━━━━━━┛
        Initialize the sending task waiting queue structure;
        If (tasks are queued in FIFO order)
                Initialize queue as follows:
                ┏━━━━━┯━━━━━━┓
                ┃Queue   │Queue     ┃
                ┃[0]     │Tail       ┃
                ┗━━━━━┷━━━━━━┛
        else (tasks are queued as priority based)
                Initialize as follows:
                ┏━━━━━━━━┯━━┯━━━━┯━━━━━━┓
                ┃Priority0      │1   │Max   │Queue    ┃
                ┃            │    │Pri    │Tail       ┃
                ┗━━━━━━━━┷━━┷━━━━┷━━━━━━┛
        Exit critical section (Interrupt Restore)
        return E_OK;
}
 

pthread: an introduction

pthread_create →  unna edhir paarkaavaa?? Vendamaa?? Sollittu po...
                            uses 'clone()' in Linux. Why not fork?
pthread_detach →(PTHREAD_CREATE_DETACHED)
                           Enna paakkaadha.. Naan andha velaya mudichittu appdiye poyiduven. Naan thaniyaa poyiruven.
                            (PTHREAD_CREATE_JOINABLE)
                            Naan vandhuduren ammaa.. Enakkaaha wait pannu... Naan ponaalum ennoda resource'la key vachittu poren. Nee dhaan key eduthuttu poyi ellaathayum oppadaikkanum. neeyum pannala'nna ellaame ambo (Zombie) dhaan...
pthread_join → Nee varra varaikkum, Wait pannuren! Nee erkanave poyirundhaai enraal, key edhuthittu vandhu, unnoda things ellaathayum release panniduren.
pthread_addr_init() → Initialize the attribute object that has to be passed to the pthread_create. Before releasing it or using in another thread, pthread_attr_destroy() needs to be called.
pthread_exit() → Release of system resources depend on the JOINABLE or not
 NPTL (Native POSIX Threads Library)
pthread_cancel → "ithoda Niruthikko!"nnu Solradha sollitten.. Appuram avan ishtam. Cancel disable aayirunda, nirutha mattaan (pthread_setcancelstate). Cancel enable pannirundhaa, two possibility. (pthread_setcanceltype) Asynchronous'la irundaa, udane niruttha chance undu. Deferred'la irundaaa, avan sonna Cancellation point'la dhaan niruthuvaan. Cancellation point is standard list of functions.
 
 
------------
 
Linux uses a 1-1 threading model, with (to the kernel) no distinction between processes and threads -- everything is simply a runnable task. *
On Linux, the system call clone clones a task, with a configurable level of sharing, among which are:
  • CLONE_FILES: share the same file descriptor table (instead of creating a copy)
  • CLONE_PARENT: don't set up a parent-child relationship between the new task and the old (otherwise, child's getppid() = parent's getpid())
  • CLONE_VM: share the same memory space (instead of creating a COW copy)
fork() calls clone(least sharing) and pthread_create() calls clone(most sharing). **
forking costs a tiny bit more than pthread_createing because of copying tables and creating COW mappings for memory, but the Linux kernel developers have tried (and succeeded) at minimizing those costs.
Switching between tasks, if they share the same memory space and various tables, will be a tiny bit cheaper than if they aren't shared, because the data may already be loaded in cache. However, switching tasks is still very fast even if nothing is shared -- this is something else that Linux kernel developers try to ensure (and succeed at ensuring).
In fact, if you are on a multi-processor system, not sharing may actually be beneficial to performance: if each task is running on a different processor, synchronizing shared memory is expensive.

* Simplified. CLONE_THREAD causes signals delivery to be shared (which needs CLONE_SIGHAND, which shares the signal handler table).
** Simplified. There exist both SYS_fork and SYS_clone syscalls, but in the kernel, the sys_fork and sys_clone are both very thin wrappers around the same do_fork function, which itself is a thin wrapper around copy_process. Yes, the terms process, thread, and task are used rather interchangeably in the Linux kernel...
 
Sample pthread program to act as TCP client and to display the transmission speed: Save the file as tcpcli.c and build with 'gcc tcpcli.c -lpthread -o tcpcli' and run with './tcpcli'.
 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define false (0)
#define true (1)
#define BUFLEN          4000    /* default length of Tx/Rx buffer */
#define NBUF            2048    /* default number of transmission */
#define MAXCON          10
int nPayload = BUFLEN;
int nbuf = NBUF;
int nSocket = 1;
int startThread = false;
struct timeval sTime, eTime;
double nbytes;      /* bytes on net */
double cput, realt; /* user, real time (seconds) */
void *tClient(void *);
static void
tvsub(tdiff, t1, t0)
    struct timeval *tdiff, *t1, *t0;
{
    tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
    tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
    if (tdiff->tv_usec < 0)
        tdiff->tv_sec--, tdiff->tv_usec += 1000000;
}
/* ******************************************************************
FUNCTION NAME: main
INPUT PARAMETER: N/A
RETURN VALUE: int
DESCRIPTION: the main thread creates all the required client threads
         mapped to available ports.
********************************************************************* */
int main ( int argc, char *argv[] )
{
    int t, retcode, threadcount=0, joincount=0, pass[MAXCON], *retval[MAXCON];
    pthread_attr_t attr;
    struct timeval td;
    nbytes = 0.0;
    if ( argc != 3 )
    {
        printf( "Enter arguments \n");
        return -1;
    }
    nSocket = atoi(argv[1]);
    if ((nSocket > 10) || (nSocket < 1)) {
        printf( "Invalid No of connections (1 ~ 10)\n");
        return -1;
    }
    nPayload = atoi(argv[2]);
    if ((nPayload > BUFLEN) || (nPayload < 10)) {
        printf( "Invalid transfer unit size (10 ~ 4000)\n");
        return -1;
    }
    if ((nSocket == 1) && (nPayload == 4000)) {
        nbuf = (16777216 * 4) / nPayload;
    } else {
        nbuf = (16777216 * 2) / nPayload / nSocket;
    }
    printf("No of sockets: %d, Tx unit size: %d, No of bufs: %d\n", nSocket, nPayload, nbuf);
    pthread_t sockThread[nSocket];
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    pthread_attr_destroy(&attr);
    for(t = 0; t < nSocket; t++)
    {
        pass[t] = t + 1;
        if(0 == (pthread_create(&sockThread[t], &attr, tClient, (void *)(pass + t))))
        {
            threadcount++;
        }
        else
        {
            perror("ERROR: pthread_create failed");
            return -1;
        }
    }
    startThread = true ;
    gettimeofday(&sTime, NULL);
    for(t = 0; t < nSocket; t++)
    {
        retcode = pthread_join(sockThread[t], (void **)(retval + t));
        if (-1 == retcode)
        {
            printf("ERROR: return code from pthread_join() is %d\n", retcode);
            break;
        }
        else
        {
            nbytes += *(retval[t]);
            joincount++;
        }
    }
    if (joincount != threadcount)
    {
        printf("exiting in incomplete state..\n");
    }
    if (nbytes > 0.0) {
        /* Get real time */
        tvsub( &td, &eTime, &sTime );
        realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
        nbytes = nSocket * nPayload * nbuf;
        printf("%.0f bytes in %.2f real seconds = %.2f Mbit/sec \n", nbytes, realt, (nbytes/realt) * 8.0 / 1024.0 / 1024.0);
    }
    pthread_exit(NULL);
    return 0;
}
/*****************************************************************************
* Send TCP data until the specified data length
*
******************************************************************************/
static int tcp_send(int cepid, char *data, int len)
{
    int ercd;
    int i;
    for (i = 0; i < len; i += ercd) {
        ercd = send(cepid, data + i, len - i, 0);
        if (ercd <= 0)
            break;
    }
    return i;   /* sent data length */
}

/* ******************************************************************
FUNCTION NAME: tClient
INPUT PARAMETER: port number is passed as an argument
RETURN VALUE: void
DESCRIPTION: this is the thread handler containing the client body,
         the thread spawned from main contains this body forming
         paralel client requesting the server.
********************************************************************* */
void *tClient(void *p)
{
    int len, total;
    int sockfd, blen = 32768;
    int retcode;
    char *sendbuff;
    int port = 5001;
    int bytesSent = 0;
    struct sockaddr_in address;
    printf("thread number %d started\n", *(int *)p);
    *(int *)p = 0;
    sendbuff = (char *)malloc(nPayload + 8);
    if(NULL != sendbuff)
    {
        memset(sendbuff, 0, nPayload + 8);
    }
    else
    {
        printf("Error in allocating buffer\n");
        pthread_exit(p);
    }
    /* Create socket for client */
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("Socket create failed") ;
        pthread_exit(p);
    }
    if (nSocket > 1) {
        if (setsockopt (sockfd, SOL_SOCKET, SO_SNDBUF, &blen, sizeof (blen)) < 0)
        {
            printf ("setsockopt SO_SNDBUF failed\n");
            pthread_exit(p);
        }
    }
    /* Name the socket as agreed with server */
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("172.16.21.20");
    address.sin_port = htons(port);
    len = sizeof(address);
    retcode = connect(sockfd, (struct sockaddr *)&address, len);
    if(retcode == -1)
    {
        perror("Connect failed");
        printf("Connect USB and do \'ifconfig usb0 172.16.21.21\'\n");
        pthread_exit(p);
    }
    while (startThread == false);
    total = 0;
    /* send TCP data until nPayload x nbuf bytes */
    for (retcode = 0; retcode < nbuf; retcode++) {
        len = tcp_send(sockfd, (char *)sendbuff, nPayload);
        if (len < nPayload) {
            if (len > 0)
                total += len;
            break;
        }
        total += len;
    }
    gettimeofday(&eTime, NULL);
    *(int *)p = total;
    free(sendbuff);
    close(sockfd);
    pthread_exit(p);
    return NULL;
}
 
 Sample pthread program to act as TCP server and to display the transmission speed: Save the file as tcpser.c and build with 'gcc tcpser.c -lpthread -o tcpser' and run with './tcpser'.
 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define false (0)
#define true (1)
#define BUFLEN          8192    /* default length of Tx/Rx buffer */
#define MAXCON          10
#define TCPAPPPORTNO    5001
unsigned int recvbuff[BUFLEN/4 + 1];
int start_count = 0, blen = 16384;
struct timeval sTime, eTime;
double nbytes, realt;      /* bytes on net */
void *tServer(void *);
static void
tvsub(tdiff, t1, t0)
    struct timeval *tdiff, *t1, *t0;
{
    tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
    tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
    if (tdiff->tv_usec < 0)
        tdiff->tv_sec--, tdiff->tv_usec += 1000000;
}
/* ******************************************************************
FUNCTION NAME: main
INPUT PARAMETER: N/A
RETURN VALUE: int
DESCRIPTION: the main thread creates all the required client threads
         mapped to available ports.
********************************************************************* */
int main ( int argc, char *argv[] )
{
    int t, retcode, threadcount=0, joincount=0;
    int sockfd, sd_current = 0;
    unsigned int addrlen;
    pthread_attr_t attr;
    struct timeval td;
    struct sockaddr_in sin, pin;
    int sockarr[MAXCON], ncon, *retval[MAXCON];
    nbytes = 0.0;
    pthread_t sockThread[MAXCON];
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    pthread_attr_destroy(&attr);
    if ( argc != 2 )
    {
        printf( "Enter arguments \n");
        return -1;
    }
    ncon = atoi(argv[1]);
    if ((ncon > MAXCON) || (ncon < 1)) {
        printf( "Invalid No of connections (1 ~ %d)\n", MAXCON);
        return -1;
    }
    /* Create socket for client */
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("Socket create failed") ;
        pthread_exit(0);
    }
    /* complete the socket structure */
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(TCPAPPPORTNO);
    if (inet_pton(AF_INET, "172.16.21.21", &(sin.sin_addr.s_addr)) <= 0)
    {
        return -1;
    }
    /* bind the socket to the port number */
    if (-1 == (bind(sockfd, (struct sockaddr *) &sin, sizeof(sin))))
    {
        perror("Bind failed") ;
        printf("Connect USB and do \'ifconfig usb0 172.16.21.21\' or wait for the address to be released\n");
        return -1;
    }
    printf("%d connections possible. Please give same number of connections on target too\n", ncon);
    for (t = 0; t < ncon; t++) {
        if ( -1 == listen(sockfd, MAXCON))
        {
            perror("Listen failed..retrying") ;
            continue;
        }
        if (ncon > 1) {
            if (setsockopt (sockfd, SOL_SOCKET, SO_SNDBUF, &blen, sizeof (blen)) < 0)
            {
                printf ("setsockopt SO_SNDBUF failed\n");
                continue;
            }
        }
        if (-1 == (sd_current = accept(sockfd, (struct sockaddr *) &pin, &addrlen)))
        {
            perror("Accept failed..retrying") ;
            continue;
        }
        printf("Connection %d accepted\n", t+1);
        if (ncon > 1) {
            if (setsockopt (sd_current, SOL_SOCKET, SO_RCVBUF, &blen, sizeof (blen)) < 0)
            {
                printf ("setsockopt SO_RCVBUF failed\n");
                continue;
            }
        }
        sockarr[threadcount] = sd_current;
        if(0 == (pthread_create(&sockThread[threadcount], &attr, tServer, (void *)(sockarr + threadcount))))
        {
            threadcount++;
        }
        else
        {
            perror("ERROR: pthread_create failed");
            return -1;
        }
    }
    for(t = 0; t < threadcount; t++)
    {
        retcode = pthread_join(sockThread[t], (void **)(retval + t));
        if (-1 == retcode)
        {
            printf("ERROR: return code from pthread_join() is %d\n", retcode);
            break;
        }
        else
        {
            nbytes += *(retval[t]);
            joincount++;
        }
    }
    if (joincount != threadcount)
    {
        printf("exiting in incomplete state..\n");
    }
    /* Get real time */
    tvsub( &td, &eTime, &sTime );
    realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
    printf("%.0f bytes in %.2f real seconds = %.2f Mbit/sec \n", nbytes, realt, (nbytes/realt) * 8.0 / 1024.0 / 1024.0);
    pthread_exit(NULL);
    return 0;
}
/*****************************************************************************
* Receive TCP data until the specified buffer size
*
******************************************************************************/
static int tcp_recv(int cepid, char *buf, int size)
{
    int ercd, i;
    for (i = 0; i < size; i += ercd) {
        ercd = recv(cepid, buf + i, size - i, 0);
        if (ercd <= 0) {
            break;
        }
    }
    return i;   /* received data length */
}

/* ******************************************************************
FUNCTION NAME: tClient
INPUT PARAMETER: port number is passed as an argument
RETURN VALUE: void
DESCRIPTION: this is the thread handler containing the client body,
         the thread spawned from main contains this body forming
         paralel client requesting the server.
********************************************************************* */
void *tServer(void *p)
{
    int len, consd, total;
    consd = *(int *)p;
/*    printf("connected socket no: %d\n", *(int *)p); */
    if (start_count == 0) {
        gettimeofday(&sTime, NULL);
    }
    total = 0;
    for (;;)
    {
        len = tcp_recv(consd, (char *)recvbuff, BUFLEN);
        if (len < BUFLEN) {
            if (len > 0)
                total += len;
            break;
        }
        total += len;
    }
    printf("Total data: %d\n", total);
    *(int *)p = total;
    gettimeofday(&eTime, NULL);
    close(consd);
    pthread_exit(p);
    return NULL;
}
 

T-Kernel based Questions and answers

How to check Stack overflow/underflow in eT-Kernel?
 
In T-kernel/extended, the stack overflow or underflow can be automatically detected, since the OS allocates 4 KB memory page just before and after the stack allocated. When the program access outside the stack, it will raise the exception without causing any damage to the data.
 
In T-kernel/compact, there is no such functionality to automatically detect the stack overflow/underflow. However, the maximum stack usage can be found using eBinder partscope. Also, in program also, it can be accessed through enabling extended debug support. It can be enabled through configuration as follows:
 
----
Configuration Root/
  Product Configuration
    Parts/
      eT-Kernel/
        T-Kernel/
          enable to reference maximum size of the stack
----
Then use the system call tdx_ref_tsk() and refer the rtsk->user_stack_peak_size and rtsk->system_stack_peak_size  fields. To use this system call, the following header file needs to be included.
 
#include
 
How to set the stack size in eT-kernel?
 
There are basic difference in the arguments and calling conventions between uT-kernel and T-kernel. For example, in uT-Kernel user space memory can be assigned as stack by enabling TA_USERBUF option. But, in copmact T-Kernel, the option has been changed as TA_USERSTACK.
 
When enabling the TA_USERSTACK, the stack can be assigned from user space memory. But, this cannot be performed if the task is running (created) at TA_RNG0 (highest) protection level.
 
Size of the stack can be assinged using stksz and sstksz. The system will allocate (stksz + sstksz) size memory for stack. In that stksz needs to be assigned by user. sstksz can be specified or can be left. If not specified, the default value from system configuration (TSysStkSz) will be used.
 
So, to control the total stack size, enable TA_SSTKSZ flag in attribute and specify the total stack size in either sstksz or in stksz or in dividing in both.

AWK programming

AWK → COBOL in C language syntax
    Processing input file of Records(Lines, delimeter NEWLINE by default) and each record with many fields (every word separated by delimeter, Space by default)
 
awk - Shell command
Program is given as first parameter sorrounded by signle quote 'whole program'
Then input file name as second parameter
Output will printed on console
 
Sample script to create folder with increasing number as suffix. Foldno.sh
 
#!/bin/bash
TARGET=/home/denso/folder/set0
DNO=$(ls -l $TARGET | grep '^d' | awk 'END{print NR}')
mkdir $TARGET/set_$DNO

Student OS

Debug channel 100% output of static as well as dynamic error output support
100%  Under OS control - No static global resources (Global data section will not be initialized, bss too will be trimmed)
0% debug required
0% Timing issues
100% clean and neat OS
 
No direct communication between tasks, only through mail.
 
job0, job1, job2,job3......job100
very easy programming