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,
6 guest(s)
that is (are) online.
 


Programowanie modułów NLM

Artykuł jest wprowadzeniem do pisania modułów NLM dla osób początkujących, które nie
wiedzą jak zacząć.
Do tworzenia modułów wykonywalnych na serwerze (NLM) potrzebne jest oprogramowanie
CodeWarrior firmy Metrowerks lub kompilator firmy Watcom.
W tym artykule opisane zostało użycie kompilatora Watcom, obecnie dostępnego na
zasadach Open Source. Niezbędne minimalne oprogramowanie jest dostępne tutaj.


1.0 Przygotowanie środowiska do pracy.

W minimalnej wersji, do tworzenia programów wykonywalnych na serwerze NetWare potrzebny
jest system DOS. Zakładając, że całość oprogramowania zainstalujemy na dysku C należy
dopisać do zbioru AUTOEXEC.BAT następujące linie:

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

Pobrane oprogramowanie kompilatora Watcom należy wgrać na dysk C z zachowaniem
zarchiwizowanej struktury plików.
W załączonym pliku znajduje się "okrojony" (ze względu na jego rzeczywistą objętość
kiludziesięciu MB) katalog NWSDK. Do właściwej pracy należy pobrać aktualną wersję
biblioteki NDK z http://developer.novell.com/ndk/nwsdkc.htm



2.0 Przykład wzorcowego modułu.

Zbiór źródłowy modułu NLM8.C znajduje się w katalogu WATCOM\NLM8.
Poniżej przedstawiony został wzorzec wielowątkowego modułu NLM. Oprócz głównego wątka
programu otwierane są dwa dodatkowe.


//==========================================
//  WZÓR WIELOWĄTKOWEGO MODUŁU NLM
//==========================================
//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 Kompilacja i linkowanie.

Kompilację modułu można wykonać wywołując zbiór komp.bat zawierający polecenie:

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

Kompilację i linkowanie modułu można wykonać wywołując zbiór link.bat zawierający polecenia:

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

Parametry linkowania zapisane są w zbiorze NLM8.LNK: 

  SYSTEM NOVELL 'WZORZEC NLM'
  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

W wyniku otrzymamy moduł NLM8.NLM, który możemy uruchomić na serwerze NetWare.
Więcej informacji dostępne jest w dokumentacji kompilatora WATCOM.

 



Portal posiada akceptację firmy Novell Polska
Wszystkie materiały dotyczące produktów 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.