I am facing a weird problem when executing Lotus Notes C API’s in multi-threaded environment.
When I execute more than 1 thread, code execution hangs with error description (Network package has not been initialized). When I execute the same piece of code by wrapping Notes API calls in critical section the code works perfectly fine.
I am not very sure whether Lotus Notes C API’s are thread safe or not. Please help me out with this.
Is it so that Notes C API’s are thread safe and I am missing an important compile/link time flag which I should be using to make the code thread safe.
#include <global.h>
#include <dname.h>
#include <ns.h>
#include <osmem.h>
#include <osmisc.h>
#include <stdio.h>
#define MAXUSERNAME 255
#define MAX_NOTES_ERROR 1024
static char* gServerName = NULL;
static int giRef = 0;
/* Uncomment following line to make code thread safe */
/#define WRAP/
#ifdef WRAP
CRITICAL_SECTION gcritAPI;
#endif
void LockCode()
{
#ifdef WRAP
EnterCriticalSection(&gcritAPI);
#endif
}
void UnlockCode()
{
#ifdef WRAP
LeaveCriticalSection(&gcritAPI);
#endif
}
DWORD WINAPI notes_thread(LPVOID data)
{
char *prefix = "notes_thread";
char szCanonServerName[MAXUSERNAME]; /* Canonicalized Name of Server */
STATUS nError;
DWORD dwLoadIndex;
HANDLE hList = NULLHANDLE;
printf("(%s) Inside notes_thread\n",prefix);
LockCode();
if(NotesInitThread() != NOERROR)
{
printf("(%s) NotesInitThread failed\n",prefix);
UnlockCode();
return 0;
}
nError = DNCanonicalize(0L,
NULL,
gServerName,
(char FAR*)szCanonServerName,
MAXUSERNAME,
NULL);
UnlockCode();
if (ERR(nError) != NOERROR) {
printf ("(%s) DNCanonicalize %s failed: %d\n", prefix, gServerName, ERR(nError));
} else {
printf ("(%s) Calling NSPingServer (%s)\n", prefix, szCanonServerName);
LockCode();
/* Call NSPingServer - only interested in result */
nError = NSPingServer (szCanonServerName, &dwLoadIndex, &hList);
UnlockCode();
if(ERR(nError) == NOERROR)
{
printf("(%s) NSPingServer call succeeded\n",prefix);
}
else
{
char szNotesError[MAX_NOTES_ERROR];
LockCode();
OSLoadString(NULLHANDLE, ERR(nError), szNotesError,
MAX_NOTES_ERROR);
UnlockCode();
printf("(%s) NSPingServer call failed (%s)\n",prefix,szNotesError);
}
if(hList != NULLHANDLE)
{
LockCode();
OSMemFree(hList);
UnlockCode();
}
}
LockCode();
NotesTermThread();
giRef--;
UnlockCode();
printf("(%s) Exiting notes_thread\n",prefix);
return 1;
}
void CreateThreads(int iNum)
{
char *prefix = "CreateThreads";
PROCESS_INFORMATION sProcessInfo;
int i = 0;
printf("(%s) Starting %d threads\n", prefix, iNum);
for(i = 0 ; i < iNum ; i++)
{
int j = i;
memset(&sProcessInfo,0,sizeof(PROCESS_INFORMATION));
CreateThread(NULL,
0,
notes_thread,
NULL,
0,
NULL);
giRef++;
}
}
int NotesInitLib()
{
char *prefix = "NotesInitLib";
int iArgc;
char *apchArgv [3];
char zTmp [512];
STATUS nError;
{
iArgc = 0;
apchArgv [iArgc++] = strdup ("C:\\Program Files\\IBM\\Lotus\\Notes");
apchArgv [iArgc] = NULL;
nError = NotesInitExtended (iArgc, apchArgv);
if (nError != NOERROR && nError != 421) { /* not ok and not unable to find notes.ini */
/* try once more 1/2 a second later */
Sleep (500);
nError = NotesInitExtended (iArgc, apchArgv);
}
for (iArgc = 0; apchArgv [iArgc] != NULL; iArgc++)
free (apchArgv [iArgc]);
if (nError != NOERROR) {
if (nError != 421) {
printf ("NotesInitExtended error: %d\n", nError);
}
printf ("Unable to Initialize Notes!\n");
return (1);
}
}
return (0);
}
int main(int argc,char *argv)
{
char *prefix = "main";
if(argc < 2)
{
printf("Insufficient arguments\n");
return 0;
}
#ifdef WRAP
InitializeCriticalSection(&gcritAPI);
#endif
gServerName = strdup(argv[1]);
printf("(%s) ServerName: %s\n",prefix,gServerName);
if(NotesInitLib())
{
printf("Notes initialization failed\n");
}
else
{
printf("(%s) Calling CreateThreads\n",prefix);
CreateThreads(10);
while(giRef != 0)
Sleep(1000);
printf("(%s) Calling NotesTerm\n",prefix);
NotesTerm();
}
#ifdef WRAP
DeleteCriticalSection(&gcritAPI);
#endif
free(gServerName);
}