e-mail   
 Menu
  Home
  Download
  Top 10 Downloads
  Last 15 New Files
  Web Links
  Tips
  Last 15 New Tips
  NLM Programming
  Admins Club





Installation and Administration






Polish Forum SUSE




Novell Connection Magazine


 
Who's Online

 There are currently,
8 guest(s)
that is (are) online.
 


NLM Programming

This article is an introduction how to start writing an NLM modules. It is dedicated to beginning programmers. To create an executable module on server side (NLM) is needed the tool Codewarrior of Metrowerks firm or the compiler of Watcom firm . In this article is described how to use Watcom compiler, which is accessible as an Open Sorce software at present. Minimum necessery software is given here.

As a result we get NLM8.NLM module which we can run on Netware serwer.


1.0 Preparing of an environment to work.

In a minimum version to create executable programs on Netware server is needed DOS system.
Assuming all software will be installed on disc C: one should add the following commands/settings to AUTOEXEC.BAT file :

  PATH C:\WATCOM\BINW
  SET INCLUDE=C:\WATCOM\H
  SET WATCOM=C:\WATCOM

Downloaded Watcom compiler software one should copy to disc C: keeping the same structure as original.
The attached file contains only customized NWSDK folder ( due to its real original size of a few dozen MB). To proper work one should download up-to-date NDK library version from http://developer.novell.com/ndk/nwsdkc.htm


2.0 An example of the model NLM module.

Source code of NLM8.C module is available in WATCOM\NLM8 directory/folder.
Below is shown a pattern of multi-thread NLM module. Apart the main thread of programm there are open two additional threads.


//==========================================
//  PATTERN OF MULTI-THREAD NLM MODULE
//==========================================
//Includes
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <nwconio.h>
#include <nwthread.h>
#include <nwenvrn.h>
#include <nwerrno.h>
#include <ntypes.h>

//Globals
int NLM_MainThreadGroupID;
      //This is the thread group ID for the main() thread
int NLM_ThreadCount = 0;
      //Keeps count of number of threads running
int NLM_Exiting = FALSE;
      //Flag that threads poll to know when to exit
int NLM_Thread1_ID;
      //Thread ID for second thread we created in main()
int NLM_Thread2_ID;
      //Thread ID for third thread we created in main()
int Thread1_ScreenHandle = NULL;
      //Handle for screen created in thread 1
//Function prototypes
void main(void);
void NLM_SignalHandler(int sig);
void Thread1Func(void *);
void Thread2Func(void *);
//같같같같같같같같같같같같같같같같같같같같같
//            *********** MAIN ********
//같같같같같같같같같같같같같같같같같같같같같
void main(void)
{
  //Increment thread count
  ++NLM_ThreadCount;              
  //Get this thread's ID from OS
  NLM_MainThreadGroupID = GetThreadGroupID();  
  
  //Register NLM_SignalHandler function for SIGTERM [UNLOAD] event
  signal(SIGTERM, NLM_SignalHandler);      
  
  //Register NLM_SignalHandler function for SIGINT [CTRL-C] event
  signal(SIGINT, NLM_SignalHandler);      
  ConsolePrintf("\nNLM8: Thread 0 (main() thread) started
 and running!\n\r");
  //////////////////////////////////
  // Body of main continues here...
  //////////////////////////////////
  
  //Let's start up a new thread
  NLM_Thread1_ID = BeginThread(Thread1Func, NULL, 8192, NULL); 
  if(NLM_Thread1_ID == EFAILURE)
  {
    ConsolePrintf("\n\rNLM8: ERROR: Could not start thread
 1. BeginThread returned: %X\n\r", NLM_Thread1_ID);
//Don't exit immediately, set NLM_Exiting flag instead NLM_Exiting = TRUE; }
  //Now let's start up another thread
  NLM_Thread2_ID = BeginThread(Thread2Func, NULL, 8192, NULL); 
  if(NLM_Thread2_ID == EFAILURE)
  {
    ConsolePrintf("\n\rNLM8: ERROR: Could not start thread
 2. BeginThread returned: %X\n\r", NLM_Thread2_ID);
//Don't exit immediately, set NLM_Exiting flag instead NLM_Exiting = TRUE; }
  //////////////////////////////////
  // Body of main ends here...
  //////////////////////////////////
  //Make sure the main() thread is the last to exit!
  while(NLM_ThreadCount != 1 || !NLM_Exiting)
    ThreadSwitchWithDelay();
  ConsolePrintf("NLM8: main() thread exiting!\n\r");
  
  //Bring thread count to zero so that the signal
  //handler can now exit, if necessary
  --NLM_ThreadCount;
  return;
}
//같같같같같같같같같같같같같같같같같같같같같
// Signal Handler
// This callback function will be called from the
// Server Console OS thread when the NLM is
// manually UNLOADed  from the console,
// or if the server is going down,
// or if SIGTERM is raise()'ed for this NLM.
//같같같같같같같같같같같같같같같같같같같같같
void NLM_SignalHandler(int sig)
{
  int handlerThreadGroupID;          
  
  handlerThreadGroupID = GetThreadGroupID();  
  SetThreadGroupID(NLM_MainThreadGroupID);  
  switch(sig)
  {
    //SIGTERM - NLM is being UNLOADed,
    //or otherwise terminated externally [e.g. Server going down]
    case SIGTERM:  
      //Set flag to tell all threads it's time to leave
      NLM_Exiting = TRUE;              
      ////////////////////////////////////////
      //NLM SDK functions may be called here//
      //Don't do your cleanup here.         //
      //Do this in each thread instead.     //
      ////////////////////////////////////////
      //Wait until all threads have terminated before leaving
      while(NLM_ThreadCount)
      {
        //This print statement is just for illustration.
        ConsolePrintf("NLM8: SignalHandler:
        Waiting for threads to terminate...\n\r");
        ThreadSwitchWithDelay();
      }
      ConsolePrintf("NLM8: SignalHandler: Done!\n\r");
      break;
    default:  
      break;
  }
  SetThreadGroupID(handlerThreadGroupID);
  return;
}
//같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
// This is the entry point for the second thread (created in main())
//같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
void Thread1Func(void *arg)
{
  arg = arg;        //suppress warnings
  //Increment thread count
  ++NLM_ThreadCount;              
  ConsolePrintf("NLM8: Thread 1 started and running!\n\r");
  //Create a screen for this thread for use by this NLM.
  //Note that this automatically becomes the current [active] screen for this
  //thread, because there are no other screens in this NLM.
  Thread1_ScreenHandle = CreateScreen("NLM TEMPLATE
   Multi-thread Screen", AUTO_DESTROY_SCREEN);
  if(Thread1_ScreenHandle == EFAILURE || Thread1_ScreenHandle == NULL)
  {
    ConsolePrintf("\n\rNLM8: ERROR: CreateScreen returned: %X\n\r",
    Thread1_ScreenHandle);
    //Don't exit immediately, set NLM_Exiting flag instead
    NLM_Exiting = TRUE;
  }
  //Thread1 run loop
  while(!NLM_Exiting)
  {
    printf("Thread 1 is printing this text!\n");
    //Press a key on this screen to terminate the NLM
    if(kbhit())
    {
      NLM_Exiting = TRUE;
      printf("Time to leave!!\n");
    }
    delay(500);        //put this thread to sleep for 500ms.
  }
  //Clean up this thread's resources
  if(Thread1_ScreenHandle != NULL)
    DestroyScreen(Thread1_ScreenHandle);
    
  //Reset to NULL so other threads won't try to use
        // it now that it has been destroyed
  Thread1_ScreenHandle = NULL;
  //Decrement thread count
  --NLM_ThreadCount;              
  ConsolePrintf("NLM8: Thread 1 shutdown...\n\r");
}
//같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
// This is the entry point for the third thread (created in main())
//같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
void Thread2Func(void *arg)
{
  arg = arg;        //suppress warnings
  //Increment thread count
  ++NLM_ThreadCount;              
  ConsolePrintf("NLM8: Thread 2 started and running!\n\r");
  //Set this thread's active screen to the screen we created in thread 1
  if(Thread1_ScreenHandle != NULL)
    SetCurrentScreen(Thread1_ScreenHandle);
  else
    NLM_Exiting = TRUE;
  
  //Thread2 run loop
  while(!NLM_Exiting)
  {
    if(Thread1_ScreenHandle != NULL)  //make sure the screen is still valid
      printf("This text comes from Thread 2!\n");
    delay(500);        //put this thread to sleep for 500ms.
  }
  //Decrement thread count
  --NLM_ThreadCount;              
  ConsolePrintf("NLM8: Thread 2 shutdown...\n\r");
}
//같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같



3.0 Compilation and linking.

Module compilation can be done by execution of komp.bat file which contains a command:

  set pgm=nlm8
  wcc386 -D2 -ms -w4 -5s -bt=NetWare -Ic:\nwsdk nlm8.c

Compilation and linking of module can be done by execution of link.bat file which contains following commands:

  set pgm=nlm8
  wcc386 -D2 -mf -w4 -5s -5r -bm -fp5 -fpi87 -eq -bt=NetWare -Ic:\nwsdk nlm8.c
  wlink @nlm8.lnk

Linking parameters are set in a file NLM8.LNK: 

  SYSTEM NOVELL 'MULTI-THREAD NLM MODULE'
  debug all
  file nlm8
  name nlm8.nlm 
  option map 
  option stack=16384
  option copyright 'Copyright by DJack Software 04/2003. All rights reserved.' 
  option version = 1.1
  import @c:\nwsdk\imports\nwsnut.imp
  import @c:\nwsdk\imports\clib.imp 
  import @c:\nwsdk\imports\dsapi.imp
  import @c:\nwsdk\imports\calnlm32.imp
  import @c:\nwsdk\imports\clxnlm32.imp
  import @c:\nwsdk\imports\netnlm32.imp
  module nwsnut.nlm
  module clib.nlm
  module calnlm32.nlm
  module clxnlm32.nlm
  module netnlm32.nlm

As a result we get NLM8.NLM module which we can run on Netware serwer.
More information is provided in documentation of WATCOM compiler.

 



Portal posiada akceptację firmy Novell Polska
Wszystkie materiały dotyczące produktw firmy Novell umieszczono za zgodą Novell Polska
Portal has been accepted by the Novell Polska
All materials concerning products of Novell firm are placed with Novell Polska consent.
NetWare is a registered trademark of Novell Inc. in the United States and other countries.
Windows is a trademark or a registered trademark of Microsoft Corporation in the United States and other countries.
Sybase is a registered trademark of Sybase Inc. in the United States of America.
Other company and product names are trademarks or registered trademarks of their respective owners.