I have created my own event loop in Tcl as below. When i run the below code using tclsh interactively, CPU Utilization is close to 0% and when i run the same run using bsub, CPU Utilization shoots up to 100%.
I have even tried making read call blocking using below and that doesn't help too.
int flag = fcntl(0, F_GETFL);
flag = flag & (~O_NONBLOCK);
(void) fcntl(0, F_SETFL, (long)flag);
What is the reason here and how do i solve this problem?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <tcl.h>
#include <errno.h>
#include <fcntl.h>
void fwStdinKeyHandler(ClientData clientData, int mask)
{
unsigned char c = 0;
int rc = read(STDIN_FILENO, &c, 1);
//printf("rc is : %d\n",rc);
while (rc < 1 && errno == EINTR) {}
}
static void MainLoop(void)
{
Tcl_CreateFileHandler(STDIN_FILENO, TCL_READABLE, fwStdinKeyHandler, NULL);
while (1) {
Tcl_DoOneEvent(0);
}
fprintf(stdout,"Exit MainLoop\n");
fflush(stdout);
}
static int Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_SetMainLoop(MainLoop);
return TCL_OK;
}
/*
* Hello_Init -- Called when Tcl loads your extension.
*/
int DLLEXPORT Cmd_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
/* changed this to check for an error - GPS */
if (Tcl_PkgProvide(interp, "Hello", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "doone_loop", Hello_Cmd, NULL, NULL);
return TCL_OK;
}
How to make?
1. File saved in,say, hello.c
2. gcc -fpic -c hello.c -I/usr/local/include
3. gcc -shared hello.o -o libcmd.so
How to run?
runme file contains:
load libcmd.so
doone_loop
/usr/bin/tclsh runme => CPU Utilization close to 0%
bsub -q interactive -m "/usr/bin/tclsh runme" => CPU Utilization close to 100%
For non-interactive shell, there is no terminal and hence, no stdin channel, so read call returns zero. So, we need to add below code in fwStdinkeyhandler after read returns 0.
if(rc==0) {
Tcl_DeleteFileHandler(0);
}