Skip to content

linux

Brushing Up My C. Building A Unix Domain Socket Client/Server (PART II)

I described in this previous blog post how to build a simplistic Unix Domain Socket client/server application.
The disadvantage with that approach is that the server can only handle one connection at a time (i.e. is not concurrent).

This blog post explains how this can be improved by using mechanisms like select(), epoll(), kqueue() etc.
Effectively all these mechanisms allow for monitoring multiple file descriptors and be called back when one or multiple of those file descriptors have data so that an action can be invoked (i.e. read, write etc).
The main differences among those are characteristics like:

  • Synchronous vs Asynchronous paradigms
  • Underlying data structures in the internals of those system calls, which play an important role on performance
  • Platforms/OS specific, as not every OS supports all the above. Some are platform agnonistic (i.e. select()), some are platform specific (i.e. epoll() is only implemented on Linux)

A superb blog post to understand the differences is this one by Julia Evans

select()

I tried to just enhance the server part of the previous blog post and I went with the select() option.
The select() system call is simpler from epoll() or kqueue() and it effectively allows for registering a number of file descriptors which are monitored for I/O events. On calling select() the thread blocks and it only unblocks when one or more file descriptors have I/O data.
The file descriptors have to manually be registered on an fd_set, which in turn is passed in the select() call. The below macros can be used to manipulate the fd_set:

  • void FD_ZERO(fd_set *set): Initialize an fd_set
  • void FD_SET(int fd, fd_set *set): Add a file descriptor to an fd_set
  • void FD_CLR(int fd, fd_set *set): Remove a file descripro from the fd_set
  • int FD_ISSET(int fd, fd_set *set): Check if a specific file descriptor, part of the fd_set is ready with I/O data

The main caveat with select() is that on every call the fd_set is cleared from the file descriptors that do not have any I/O data on that cycle, hence the developer has to manually re-register all the file descriptors again, which is also descripted in the select() documentation

Note well: Upon return, each of the file descriptor sets is modified in place to indicate which file descriptors are currently "ready". Thus, if using select() within a loop, the sets must be reinitialized before each call.

Having said that, the server.c file now looks like:

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "stddef.h"

#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h> 
#include <sys/un.h>
#include <netinet/in.h>
#include "sys/syscall.h"
#include <sys/select.h>
#include <errno.h>

#include "af_unix_sockets_common.h"

int pumpData(int fd);
int cleanupConnections(int *connections, int idx);

/*
* Open a `AF_UNIX` socket on the `path` specified. `bind()` to that address, `listen()` for incoming connections and `accept()`. Finally, wait for input from the socket and print 
* that to the `stdout`. When one connection is closed, wait for the next one.
*/
void server(char *path) {
    printf("Starting AF_UNIX server on Path=%s\n", path);
    AFUnixAddress *domainSocketAddress = open_af_unix_socket(path);

    int hasBind = bind(domainSocketAddress->fd, (struct sockaddr *)domainSocketAddress->address, sizeof(struct sockaddr));
    if(hasBind == -1){
        fprintf(stderr, "Failed to bind AF_UNIX socket on Path=%s. ErrorNo=%d\n", path, errno);
        cleanup(domainSocketAddress->fd, path);
        exit(errno);
    }

    int isListening = listen(domainSocketAddress->fd,  10);
    if(isListening == -1) {
        fprintf(stderr, "Failed to listen to AF_UNIX socket on Path=%s. ErrorNo=%d\n", path, errno);
        cleanup(domainSocketAddress->fd, path);
        exit(errno);
    }

    fd_set readfds;
    int maxFD = domainSocketAddress->fd;
    FD_ZERO(&readfds);
    FD_SET(domainSocketAddress->fd, &readfds);

    int openConnections[FD_SETSIZE];
    int closedConnections[FD_SETSIZE] = {0};// indices to openConnections that have clo
    int nextIdx = 0;

    fprintf(stdout, "Start accepting connections on Path=%s\n", path);
    while(TRUE) {
        int retVal = select(maxFD + 1, &readfds, NULL, NULL, NULL);
        if(FD_ISSET(domainSocketAddress->fd, &readfds)) {

            int connFd = accept(domainSocketAddress->fd, NULL, NULL);
            if(connFd == -1) {
                fprintf(stderr, "Error while accepting connection. Error=%s, ErrorNo=%d\n", strerror(errno), errno);
                cleanup(domainSocketAddress->fd, path);
                exit(errno);
            }
            fprintf(stdout, "New AF_UNIX connection added\n");

            openConnections[nextIdx++] = connFd;
            maxFD = maxFD >= connFd ? maxFD : connFd;
            FD_SET(connFd, &readfds);
        } else {
            for(int i = 0; i < nextIdx;i ++) {
                if(FD_ISSET(openConnections[i], &readfds)) {

                    if(!pumpData(openConnections[i])){
                        FD_CLR(openConnections[i], &readfds);
                        openConnections[i] = -1;// denotes that connection has closed
                    }
                }
            }

            nextIdx = cleanupConnections(openConnections, nextIdx);
        }

        // re-add all active FDs to fd_set
        FD_SET(domainSocketAddress->fd, &readfds);
        for(int i = 0; i < nextIdx;i ++) {
            FD_SET(openConnections[i], &readfds);
        }
    }

    cleanup(domainSocketAddress->fd, path);
}

int pumpData(int connFd) {
    char buf[BUFSIZ];
    int bytes = read(connFd, buf, BUFSIZ);
    if(bytes <= 0) {
        fprintf(stdout, "Connection closed\n");
        return FALSE;
    }
    write(1, buf, bytes);
    return TRUE;
}

int cleanupConnections(int *connections, int idx) {
    int temp[idx];
    int next = 0;
    for(int i = 0; i < idx;i++) {
        if(connections[i] != -1) {
            temp[next++] = connections[i];
        }
    }

    memcpy(connections, temp, sizeof(temp));
    return next;
}

The Changes

The few changes that worth mentioning are the below:

  • We first registered the AF_UNIX sockets file descriptor on the fd_set that is passed into the select() call.
  • On every call to select(), the first check to be done is that if the socket file descriptor has I/O data, which means a new connection. If so the server accept() that connection
if(FD_ISSET(domainSocketAddress->fd, &readfds)) {
    int connFd = accept(domainSocketAddress->fd, NULL, NULL);
    ...
  • After accepting a connection, that connection's file descriptor has to be added to the fd_set so that it can be monitored for I/O events
FD_SET(connFd, &readfds);
  • For every open connection, the program checks if the corresponding file descriptor has I/O data, and if so the server reads those data. Worth noting that when a connection closes, this also means an I/O signal, hence the program needs to check and remove the closed file descriptor from the monitoring fd_set
if(FD_ISSET(openConnections[i], &readfds)) {
    if(!pumpData(openConnections[i])){
        FD_CLR(openConnections[i], &readfds);
        openConnections[i] = -1;// denotes that connection has closed
    }
}
  • Finally, as mentioned above, after select() returns it will only contain file descriptors that have data on the fd_set. Any previously added file descriptors that did not have I/O data on that cycle are removed, hence needs to be re-added. Luckily, according to the select() documentation there is no harm trying to re-set a file descriptor that is already in the fd_set hence we just loop over the known file descriptors and re-add them all on the fd_set

FD_SET() This macro adds the file descriptor fd to set. Adding a file descriptor that is already present in the set is a no-op, and does not produce an error.

// re-add all active FDs to fd_set
FD_SET(domainSocketAddress->fd, &readfds);
for(int i = 0; i < nextIdx;i ++) {
    FD_SET(openConnections[i], &readfds);
}

Conclusion

The changes needed to allow for multiplexing of different connections were minimal and did not radically affect the programs logic. Someone can take this example and enhance it further. Some suggestions would be:

  • Try epoll() instead of select()
  • Instead of just reading what the client has sent and printing it out to the console, broadcast the message to all clients connected at that time

Brushing Up My C. Building A Unix Domain Socket Client/Server (Part I)

I haven't really done much C in my professional career. There were a couple of times that I had to look into some C code, but not really create any kind of system in C. Most of my interaction with the C programming language dates back to university times.
I always liked C though. For its simplicity as a language, for its small surface as a language (i.e. not bloated with tons of features) and finally for the perfect, artistic, abstraction it provides on top of the hardware, which is so close to the metal but at the same time hiding the complexities and providing just about the right amount of abstractions.

For all the above and thanks to the lockdown and the plenty of me-time that I now have, I decided to revise C and try to put some of its features in practice by gradually building a very simple application.

Revising Using a Book

I didn't want to follow any tutorials or knowledge in Google, hence I picked up a book in order to revise. Even though there are a couple of great books for C out there, for me it was a no brainer to actually revise one of the best books in my library The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie.
This book is written back in 1988, but personally I find it to be one of the best technical books I ever read. I read the entire book in about 2 weeks, and in parallel I was trying to do some of the plenty exercise that each chapter has. By doing so, I refreshed some of my knowledge in C and got a fresh overview of its features as a language.

Deciding On A Simple Application

After finishing the book I decided it would be nice to put some of the concepts in action and build something small, trying to use some of the features I just revised. I wanted something that wouldn't take me much time (as it would mainly be a playground, rather than a side project), but at the same time also give me some knowledge.
I was always interested and fairly familiar with network servers. I have an understanding of the underlyling kernel space functions that take place in socket programming, but I have always been using abstractions on top of this, mainly through Java frameworks. So I decided to build something around that concept, and as I wanted to keep it fairly simple and because I hadn't really use this feature in the past, I concluded building a client/server applications using Unix Domain Sockets makes sense and most likely would fullfill most of my requirements.

Simplifying it a lot, a Unix Domain Socket is like any other socket (i.e. internet socket), but it can only be used for inter-process communication on the host it is opened, as it is actually backed by the filesystem.

Rules Of Engagement

In order to actually build this all by myself (I could just google an example and get the solution in 5 minutes), I decided to impose some very basic rules:

  • I could use the book I read as a reference
  • I could use man7.org as a reference for system calls
  • I could not use any other internet resource that provided a ready baked solution
  • The purpose of this application was not to be cross-platform. I was mainly interested making it work in my Mac and effectively in BSD like systems

The Code

I decided to split the code into different source (.c) files:

  • af_unix_sockets.c: The file containing the main() method and basic logic for parsing the command line arguments in order to start a client or a server
  • af_unix_sockets_common.h: A header file containing common definitions and the prototypes for the different methods, that client or server implements and also the defininion of a simple type AFUnixAddress storing a file descriptor and the actual socket address
  • af_unix_sockets_common.c: A source file containing some common methods
  • af_unix_sockets_server.c: The server implementation, to be called by the main method in af_unix_sockets.c
  • af_unix_sockets_client.c: The client implementation, to be called by the main method in af_unix_sockets.c

The Header File

As described above af_unix_sockets_common.h is a header file defining the prototypes of various functions (which I view as the public interface) to be implemented by parts of the system and to be called by other parts.
Additionally, the header defines a type, which I mainly created for Part II of this post, encapsulating the file descriptor of an opened unix domain socket and also its address.

#define TRUE 1
#define FALSE 0
#define CLIENT "client"
#define SERVER "server"

typedef struct af_unix_address {
    int fd;
    struct sockaddr_un *address;
} AFUnixAddress;

AFUnixAddress * open_af_unix_socket(char *);
void cleanup(int fd, char *path);

void server(char *path);

void client(char *path);

The Common File

I wanted to have a common file, just for the shake of it, to be able to export some common functionality that is shared between the server and the client.

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "stddef.h"

#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#include "af_unix_sockets_common.h"

/*
 * @return AFUnixAddress type, containing the address and the file descriptor for the opened unix domain socket  
*/
AFUnixAddress *open_af_unix_socket(char *path) {
    int fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(fd == -1) {
        fprintf(stderr, "Failed to open AF_UNIX socket. ErrorNo=%d\n", errno);
        cleanup(fd, path);
        exit(errno);
    }

    AFUnixAddress *af_unix_socket = (AFUnixAddress *)malloc(sizeof(AFUnixAddress));
    af_unix_socket->address = (struct sockaddr_un *)malloc(sizeof(struct sockaddr_un));
    af_unix_socket->fd = fd;
    af_unix_socket->address->sun_family = AF_UNIX;
    strcpy(af_unix_socket->address->sun_path, path);
    return af_unix_socket;
}

/*
* Clean up an opened file descriptor opened for 
*/
void cleanup(int fd, char *path) {
    close(fd);

    remove(path);

    if(fd != -1) {
        fprintf(stderr, "Failed to successfully close socket. ErrorNo=%d\n", errno);
    }
}

The common file is very simple, containing just two methods, one that opens a Unix Domain Socket for the specified path that was passed in and returning an AFUnixAddress which is a type defined in the af_unix_sockets_common.h file, containing the actual socket's address and the file descriptor corresponding to that socket.
The file descriptor is needed for later use, to invoke system calls on it. Finally, worth mentioning that the Unix Domain Socket opened is a SOCK_STREAM one, which based on the documentation follows TCP semantics, as opposed to SOCK_DGRAM which follows UDP semantics.

The Client

The client's behavior is defined in its own file and is pretty simplistic. A path is passed in specifying the filepath for the Unix Domain Socket. Then a socket is opened for that path and an invocation to #connect() method, passing in the file descriptor associated with the socket, forces the connection to be established.
Finally, the client reads from stdin and writes that to the socket invoking the write() method.

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "stddef.h"
#include "unistd.h"

#include <sys/socket.h>
#include <sys/types.h> 
#include <sys/un.h>
#include "sys/syscall.h"
#include <errno.h>

#include "af_unix_sockets_common.h"

/*
* AF_UNIX socket client, obtains an ```AFUnixAddress``` by opening the socket to the specified ```path``` and then invoking ```#connect()``` on the socket's file descriptor.
* Finally, the client reads input from ```stdin``` and writes that to the socket.
*/
void client(char *path) {
    fprintf(stdout, "Starting AF_UNIX client on Path=%s\n", path);
    AFUnixAddress *domainSocketAddress = open_af_unix_socket(path);
    printf("AF_UNIX client socket on Path=%s opened with fd=%d\n", domainSocketAddress->address->sun_path, domainSocketAddress->fd);

    int isConnected = connect(domainSocketAddress->fd, (struct sockaddr *)domainSocketAddress->address, sizeof(struct sockaddr));
    if(isConnected == -1) {
        fprintf(stderr, "Failed to connect to Path=%s. ErrorNo=%s\n", domainSocketAddress->address->sun_path, strerror(errno));
        cleanup(domainSocketAddress->fd, domainSocketAddress->address->sun_path);
        exit(errno);
    }

    char line[1024];
    while(fgets(line, 1024, stdin) != NULL) {
        int size = 0;
        for(;line[size] != '\0'; size++){
        }
        if(size == 0) {
            break;
        }
        int bytes = write(domainSocketAddress->fd, line, size);
    }

    cleanup(domainSocketAddress->fd, domainSocketAddress->address->sun_path);
    exit(0);
}

The Server

The server follows the same pattern with that of the client. The only difference is the system calls involved in order to bind to the opened socket and start listening. More specifically, after the socket is created
a call to bind() connects the file descriptor with the address of the socket. Then a call to listen() allows the socket to wait
for incoming connections, and finally a call to accept() accepts the first enqued connection request and retrieves a file descriptor for that connection. That file descriptor can
be passed in the read() system call to read incoming bytes. Note, that we had to call accept() because we marked the domain socket as a SOCK_STREAM one,
hence effectively a connection oriented socket.

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "stddef.h"
#include "unistd.h"

#include <sys/socket.h>
#include <sys/types.h> 
#include <sys/un.h>
#include "sys/syscall.h"
#include <errno.h>

#include "af_unix_sockets_common.h"

/*
* Open a ```AF_UNIX``` socket on the ```path``` specified. ```#bind()``` to that address, ```#listen()``` for incoming connections and ```#accept()```. Finally, wait for input from the socket and print 
* that to the ```stdout```. When one connection is closed, wait for the next one.
*/
void server(char *path) {
    printf("Starting AF_UNIX server on Path=%s\n", path);
    AFUnixAddress *domainSocketAddress = open_af_unix_socket(path);

    int hasBind = bind(domainSocketAddress->fd, (struct sockaddr *)domainSocketAddress->address, sizeof(struct sockaddr));
    if(hasBind == -1){
        fprintf(stderr, "Failed to bind AF_UNIX socket on Path=%s. ErrorNo=%d\n", path, errno);
        cleanup(domainSocketAddress->fd, path);
        exit(errno);
    }

    int isListening = listen(domainSocketAddress->fd,  10);
    if(isListening == -1) {
        fprintf(stderr, "Failed to listen to AF_UNIX socket on Path=%s. ErrorNo=%d\n", path, errno);
        cleanup(domainSocketAddress->fd, path);
        exit(errno);
    }

    fprintf(stdout, "Start accepting connections on Path=%s\n", path);
    while(TRUE) {
        int connFd = accept(domainSocketAddress->fd, NULL, NULL);
        if(connFd == -1) {
            fprintf(stderr, "Error while accepting connection. Error=%s, ErrorNo=%d\n", strerror(errno), errno);
            cleanup(domainSocketAddress->fd, path);
            exit(errno);
        }

        char buf[BUFSIZ];
        while(TRUE){
            int bytes = read(connFd, buf, BUFSIZ);
            if(bytes <= 0) {
                fprintf(stdout, "Connection closed\n");
                break;
            }
            write(1, buf, bytes);
        }
    }

    cleanup(domainSocketAddress->fd, path);
}

The Main Method

The file that contains the program's main method, reads the command line arguments, does some rudimentary parsing and based on what was passed creates an AF_UNIX socket server or client.

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "stddef.h"
#include "unistd.h"

#include <sys/socket.h>
#include <sys/types.h> 
#include <sys/un.h>
#include "sys/syscall.h"
#include <errno.h>

#include "af_unix_sockets_common.h"

const static char *USAGE = "Usage af_unix_socket --type [server|client] --path [path]\n";

int main(int argc, char **argv){
    if(argc != 5) {
        fprintf(stderr, "%s", USAGE);
        exit(-1);
    }

    char *type = NULL;
    char *path = NULL;
    char *nextParam;

    int idx=1;
    int expectFlag = TRUE;
    while(idx < 5) {
        if(strstr(&(*argv[idx]), "--") != NULL) {
            if(strcmp("--type", &(*argv[idx])) == 0) {
                nextParam = (char *)malloc(32);
                type = nextParam;
            } else if(strcmp("--path", &(*argv[idx])) == 0) {
                nextParam = (char *)malloc(32);
                path = nextParam;
            } else {
                fprintf(stderr, "%s", USAGE);
                exit(-1);
            }
            expectFlag = FALSE;
        } else {
            if(expectFlag) {
                fprintf(stderr, "Expected flag for positional argument %d. %s", idx, USAGE);
                exit(-1);
            }
            size_t paramSize = sizeof(&(*argv[idx]));
            memcpy(nextParam, &(*argv[idx]), paramSize);
        }
        ++idx;
    }

    if(type == NULL || path == NULL) {
        fprintf(stderr, "%s", USAGE);
        exit(-1);
    }

    fprintf(stdout, "Initializing AF_UNIX for Type=%s, Path=%s\n", type, path);
    if(strcmp(type, SERVER) == 0) {
        if(access(path, F_OK) != -1) {
            fprintf(stdout, "File=%s already exists. Deleting file to be used by AF_UNIX server\n", path);
            if(remove(path) != 0) {
                fprintf(stderr, "Failed to remove existing File=%s. File cannot be used for AF_UNIX server\n", path);
                exit(-1);
            }
        }

        server(path);
    } else if(strcmp(type, CLIENT) == 0) {
        client(path);
    } else {
        fprintf(stderr, "Unknown Type=%s\n", type);
    }
    return 0;
}

Compiling And Running The Program

As now we have all the building blocks, we can actually compile, link and run the program. Based on the operating system someone is running they will need a compatible compiler. Some standard choices are GCC or Clang.
I have personally used Clang as it is the standard on a MacOS system.

Compiling and linking the different files together can plainly be done by:

clang af_unix_sockets_common.c af_unix_sockets.c af_unix_sockets_client.c af_unix_sockets_server.c -o af_unix_sockets

Running the server:

af_unix_sockets --type server --path /tmp/af_unix_socket_example

Running the client:

af_unix_sockets --type client --path /tmp/af_unix_socket_example

Why Part I

This post is named Part I. The main reason behind this is that this program only accepts one connection at a time. A more scalable way of writing this program is by using a selector mechanism (i.e. select(), epoll(), kqueue()) which will allow for connection multiplexing and concurrent handling of those connections.
This will be described in a Part II of this blog and hopefully it will not need many alterations on the code above.

Identifying a high-CPU Java Thread

High CPU utilization Java application

Every now and then we find ourselves in situations when a single Java process is consuming a high percentage of CPU.

After investigating and ruling out high CPU because of continuous GC cycles or other pathogenic reasons, we find ourselves in a situation that we need to identify the business logic that causes those CPU spikes. An easy way of doing so is try to identify the thread(s) that is consuming most of the CPU and try to pinpoint the caveat.

There are a few utilities (i.e. top, htop) that let us see a process as a tree along with the threads that live inside that process' space. After identifying the thread's ID, it is pretty easy to translate the ID to its HEX value and identify the actual thread in a Java application (i.e. by taking a thread dump).

Example

As an example the following Java program, uses two application thread's (main thread and a thread created by the user), one thread is spinning forever generating random values. The main thread occasionally, reads those random values.

https://github.com/nikkatsa/nk-playground/blob/master/nk-dummies/src/main/java/com/nikoskatsanos/spinningthread/SpinningThread.java

It is expected that this would be a high CPU utilization application (see above image).

Find the Rogue Thread

After identifying the Java program's PID (i.e. with jps or something like ps, top, htop), we can run an application like htop as below

htop -p${PID}

A user can view that isolated process along with its threads. Usually htop would show user space threads by default, but if not is easy to do by going to the setup page and selecting the appropriate option on Setup -> Display Options.

Then a user should see an image like the below.

That shows the application's PID along with its threads, reporting the metrics (CPU, Memory etc) for each thread. From there someone can easily identify that thread 12820 is consuming a great percentage of CPU, hence it should be our caveat.

Translating Thread's ID to HEX

The next step would be to translate that thread's decimal ID to its HEX value, which is: 0x3214

Getting a thread dump

Knowing the thread's HEX value, the user can take a thread dump and easily locate the thread and its stack trace.

Full thread dump Java HotSpot(TM) Client VM (25.65-b01 mixed mode):

"Attach Listener" #8 daemon prio=9 os_prio=0 tid=0x64900800 nid=0x3340 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Spinner" #7 daemon prio=5 os_prio=0 tid=0x6442a800 nid=0x3214 runnable [0x6467d000]
   java.lang.Thread.State: RUNNABLE
        at java.util.concurrent.ThreadLocalRandom.nextDouble(ThreadLocalRandom.java:442)
        at com.nikoskatsanos.spinningthread.SpinningThread.spin(SpinningThread.java:16)
        at com.nikoskatsanos.spinningthread.SpinningThread$$Lambda$1/28014437.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
        - <0x659c2198> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"Service Thread" #6 daemon prio=9 os_prio=0 tid=0x76183c00 nid=0x3212 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C1 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x76180c00 nid=0x3211 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x7617f000 nid=0x3210 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x76162000 nid=0x320f in Object.wait() [0x64f9c000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x65806400> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x65806400> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
        - None
"C1 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x76180c00 nid=0x3211 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x7617f000 nid=0x3210 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x76162000 nid=0x320f in Object.wait() [0x64f9c000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x65806400> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x65806400> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
        - None

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x76160800 nid=0x320e in Object.wait() [0x64fec000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x65805ef8> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
        - locked <0x65805ef8> (a java.lang.ref.Reference$Lock)

   Locked ownable synchronizers:
        - None

"main" #1 prio=5 os_prio=0 tid=0x76107400 nid=0x320c waiting on condition [0x762b1000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at com.nikoskatsanos.spinningthread.SpinningThread.main(SpinningThread.java:40)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=0 tid=0x7615d400 nid=0x320d runnable

"VM Periodic Task Thread" os_prio=0 tid=0x76185c00 nid=0x3213 waiting on condition

JNI global references: 310

The nid value (nid=0x3214) should match the HEX value of the thread's decimal ID

As seen, in the above case is obvious that thread with name 'Spinner' is the high CPU utilization thread we are looking for. After this point the user can investigate the application's logic and determine the root cause.

Introduction

I use Vim quite often in my day to day activities. I do not use it to write code on it, but I tend to find myself logged into a linux host, where I need to edit or update files. Vim is my editor of choice for doing that.

I am not really an expert on Vim, and I tend to use a particular set of commands, hence I decided to summarize the most common commands and shortcuts I use and have this blog post as a cheatsheet whenever I want to refresh my memory.

VIM Command Categories

I tried to group the commands I use into categories like Navigation, Edit, Search and Options.

Navigating in VIM can be done using the arrows. This navigates the cursor wherever the user wants. However, as VIM is really optimized to do everything with keyboard, in the most efficient way, navigation can also be achieved with keys 'h', 'j', 'k', 'l'. Those keys map nicely into the user's fingers, without the need to move your hand to reach the arrows.

Another very common function I find myself doing is going to lines. Someone can switch on line number by :set numbers (see options section). Moving directly to a line is as simple as ${lineNumber}G, which can be read as 'go to line ${lineNumber}'.

Additionally moving to absolute positions like the file's start or end, or to the begginning or end of a line is also fairly common.

Moving one word at a time, or a continuous block (like a camel case word) can be achieved with 'w' and 'W' respectively

Edit

I have grouped actions like inserting characters, deleting character, copying and pasting under the Edit category

Operations like copying and pasting are fairly common when editing files on a unix host

Search commands are very useful either in VIM or in less. Fortunately enough both tools have the same mechanism for searching

VIM can highlight any found search terms by setting the option :set hlsearch (see options section)

Options

VIM is highly customizable. User can set a profile with the desired properties and VIM behaviour at .vimrc file. The most common options I personally used are the below.