Handicapping a Thread: Death to Your Application?
Articles and Tips: article
Developer Support Engineer
Developer Support
E DEREK ROWLEY
Owner
Network Business Solutions
01 May 1996
Because NetWare can execute only one thread at a time, only the currently running thread has control of the CPU. When a thread is given control of the CPU, the thread remains in control until it either runs to completion or relinquishes control. When a thread is actively executing, only hardware interrupts can temporarily interfere with its execution. No other thread can interfere regardless of priority. NetWare provides a method for tracking and monitoring threads that don't relinquish control of the server's CPU within a reasonable time. NetWare also provides an option to monitor a thread's CPU usage through Monitor's Scheduling Information option. Lastly, CLIB includes two APIs for handicapping threads: SetThreadHandicapand GetThreadHandicap.
This DevNote discusses the console SET parameter SET DISPLAY RELINQUISH CONTROL ALERTS, which allows you to track threads that do not give up CPU control within a given time period. A program called HANDICAP.C is then described. It allows the user to enter a handicap amount on the command line. Last of all, a listing and discussion of HOG.NLM are included; this module offers valuable insights into thread activity.
Introduction
The NetWare 4.10 Operating System allows NLM applications to create multiple threads. Each thread represents a single path of execution such as a main function or a library function. The Intel CPU architecture allows only one instruction to be executed at a time; hence only one thread can be running at a time. Because NetWare can execute only one thread at a time, only the currently running thread has control of the CPU. When a thread is given control of the CPU, the thread retains control until it either runs to completion or relinquishes control. When a thread is actively executing, only hardware interrupts can temporarily interfere with its execution. No other thread can interfere regardless of priority.
You might ask, "What happens if a thread monopolizes the CPU?" It is possible to bring a NetWare server to its knees if a misbehaving thread uses too much of the CPU's processing time. Programming in the NetWare environment has always depended on "nice guy" rules, where programmers are expected to create NLMs with threads that regularly yield the CPU to other threads. However, experience shows that this "nirvana" doesn't always exist.
NetWare provides a method for tracking and monitoring threads that don't relinquish control of the server's CPU within a reasonable time. NetWare also provides an option to monitor a thread's CPU usage through Monitor's Scheduling Information option. Lastly, CLIB includes two APIs for handicapping threads: SetThreadHandicapand GetThreadHandicap.
Using NetWare's SET Command
The NetWare operating system, in order to maintain fair use of the system CPU, has the ability to permanently handicap a thread. However, NetWare is designed to notify the system administrator and not actually handicap a misbehaving thread. The handicapping needs to be done by monitoring software. NetWare has a SET parameter, which will place a warning message on the server console when a thread uses the CPU for too long. NetWare defines "too long" as seven clock ticks or approximately 385 milliseconds.
Type
SET DISPLAY RELINQUISH CONTROL ALERTS = ON
at the NetWare server prompt. This causes the following message when a thread doesn't relinquish control frequently enough.
Process did not relinquish control frequently. Module: <name of offending module<< Code offset in module: <value<
Type the code for HANDICAP.C (Listing 1) and compile it using the Watcom or some other suitable compiler. This program allows the user to enter a handicap amount on the command line. If no value is entered, a default value of five is used. A signal/SIGTERM is set up to allow proper unloading. Then RegisterForEvent is called with the parameter EVENT_NO_RELINQUISH_CONTROL to monitor any thread using too much CPU time. Then SuspendThread is called to put the NLM to sleep until unloaded.
When a thread uses too much CPU time, according to the NetWare definition, NetWare calls the NoRelinquishProcedure, which is passed into RegisterForEvent. The GetThreadHandicap CLIB function is then called to get the current handicap value of the running thread. This value is then incremented by either 5 (default) or the value passed in on the command line. The value is then implemented by calling CLIB's SetThreadHandicap. When the NLM unloads, the SIGTERM handler is called, unregistering the event and resuming the original thread initiated in main. This is the only way you can properly terminate HANDICAP.NLM. Make sure you have MONITOR.NLMloaded and then load HANDICAP.NLM.
Using HOG.NLM
To finish, type COMPILE and load HOG.NLM(Listing 2). HOG.NLM, like the nickname of the famous motor bike, is nasty and gnarly because it creates a thread and doesn't give up control of the server's CPU frequently. In HOG.NLM, an opening message is printed, a signal/SIGTERM is set up for the unload message, and a loop is entered that counts to a large number. After the large number is reached, control of the CPU is relinquished with ThreadSwitchWithDelay, a short delay is taken via delay, and count is set back to 1. This process is then repeated. If you switch over to the System Console you will notice a message like this:
2-23-96 8:26:19 pm: SERVER-4.10-831 hog__p 0 Process did not relinquish control frequently Module: hog Code offset in module: 44h.
If you switch to the NetWare Monitor Utility select Scheduling Information under the Available Options menu; you will notice the hog process under the Process Name column. Looking across that column you will see the Sch Delay increment, according to the value you set in HANDICAP.NLM (default is 5). This value indicates the amount of other threads that will run before HOG.NLM's thread runs again. You will also notice that the Time and Load values increment accordingly when HOG.NLM is utilizing the server's CPU. Note:HOG.NLM also needs to be unloaded to properly terminate.
In summary, NetWare provides a method for tracking threads that don't relinquish control of the server's CPU within a reasonable time. NetWare provides a way to monitor this with the SET DISPLAY RELINQUISH CONTROL ALERTS console SET parameter. NetWare also provides an option to monitor a thread's CPU usage through MONITOR's Scheduling Information option. Lastly, to handicap those pesky threads that monopolize all of your server's precious CPU time, CLIB provides two APIs, SetThreadHandicap and GetThreadHandicap.
E Derek Rowley is the owner of Network Business Solutions. He can be reached at (801) 762-0866.
Listings
Listing 1 Handicap.c
/************************************************************************** ** File: handicap.c ** ** Description: ** ** Example program for monitoring threads. ** ** This program demonstrates how to use RegisterForEvent Services ** to monitor if a thread is using the system CPU too long. ** ** ** DISCLAIMER ** ** Novell, Inc. makes no representations or warranties with respect to ** any NetWare software, and specifically disclaims any express or ** implied warranties of merchantability, title, or fitness for a ** particular purpose. ** ** Distribution of any NetWare software is forbidden without the ** express written consent of Novell, Inc. Further, Novell reserves ** the right to discontinue distribution of any NetWare software. ** ** Novell is not responsible for lost profits or revenue, loss of use ** of the software, loss of data, costs of re-creating lost data, the ** cost of any substitute equipment or program, or claims by any party ** other than you. Novell strongly recommends a backup be made before ** any software is installed. Technical support for this software ** may be provided at the discretion of Novell. ** ** QMK386 options used: ** ** None ** ** Programmers: ** ** Ini Who Firm ** --------------------------------------------------------------------- ** KDB Kevin Burnett Novell Developer Support ** EDR E Derek Rowley Network Business Solutions ** ** ** History: ** ** When Who What ** --------------------------------------------------------------------- ** 2-23-1996 KDB First code. ** 2-23-1996 EDR First code. */ /************************************************************************** ** Compiler setup. */ /*---------------------------------------------------------------------- ** ANSI */ #include <stdlib.h<< #include <stdio.h<< #include <signal.h<< /*---------------------------------------------------------------------- ** NetWare */ #include <process.h<< #include <advanced.h<< /************************************************************************** ** Global variables. */ int tid = 0; int cid = 0; int handicapDelta = 5; LONG ehndl = 0; /************************************************************************** ** FailureToRelinquishProcedure is called by the server operating system ** when a thread has held control of the system CPU too long. */ void FailureToRelinquishProcedure(LONG param) { int hc; /************************************************************************** ** Adjust the handiap of the thread. */ hc = GetThreadHandicap(param); hc += handicapDelta; SetThreadHandicap(param, hc); } /************************************************************************** ** Unload routine. */ void UnloadAppRoutine() { /************************************************************************** ** Unregister the event. */ UnregisterForEvent(ehndl); ResumeThread(tid); } /************************************************************************** ** main procedure. */ int main(int argc, char *argv[]) { argc = argc; /* make the compiler happy. */ printf ("Process Handicap Watchdog.\n");" printf ("Usage: load handicap [n] where n = handicap value.\n\n");" /************************************************************************** ** Process command line. */ if (argv[1]) handicapDelta = atoi(argv[1]); /************************************************************************** ** Setup for unload. */ tid = GetThreadID(); cid = GetThreadContextSpecifier(tid); signal(SIGTERM, UnloadAppRoutine); /************************************************************************** ** Install relinquish control event handler. */ ehndl = RegisterForEvent(EVENT_NO_RELINQUISH_CONTROL, FailureToRelinquishProcedure, NULL); if (!ehndl) { printf("ERROR: Could not register for EVENT_NO_RELINQUISH_CONTROL.\n");" return -1; } /************************************************************************** ** Now sleep until unloaded. */ printf("INIT: Installation successful. Handicap delta = %d.\n\n", handicapDelta);" SuspendThread(tid); return 0; }
Listing 2 - Hog.c
/************************************************************************** ** File: hog.c ** ** Description: ** ** Example program to hog the server CPU. ** ** This program will monopolize the server CPU long enough to cause the ** server to issue an alert indicating that the process did not ** relinquish control frequently enough. ** ** ** DISCLAIMER ** ** Novell, Inc. makes no representations or warranties with respect to ** any NetWare software, and specifically disclaims any express or ** implied warranties of merchantability, title, or fitness for a ** particular purpose. ** ** Distribution of any NetWare software is forbidden without the ** express written consent of Novell, Inc. Further, Novell reserves ** the right to discontinue distribution of any NetWare software. ** ** Novell is not responsible for lost profits or revenue, loss of use ** of the software, loss of data, costs of re-creating lost data, the ** cost of any substitute equipment or program, or claims by any party ** other than you. Novell strongly recommends a backup be made before ** any software is installed. Technical support for this software ** may be provided at the discretion of Novell. ** ** QMK386 options used: ** ** None ** ** Programmers: ** ** Ini Who Firm ** --------------------------------------------------------------------- ** KDB Kevin Burnett Novell Developer Support ** ** ** History: ** ** When Who What ** --------------------------------------------------------------------- ** 2-23-1996 KDB First code. */ /************************************************************************** ** Compiler setup. */ /*---------------------------------------------------------------------- ** ANSI */ #include <stdio.h<< #include <signal.h<< /*---------------------------------------------------------------------- ** NetWare */ #include <process.h<< /************************************************************************** ** UnloadAppRoutine prints an unload message when nlm is unloaded. */ void UnloadAppRoutine() { printf("Hog: Unloaded.\n");" return; } /************************************************************************** ** main procedure. */ main(void) { long count = 1; printf("Hog: Program to hog server CPU loaded.\n");" /************************************************************************** ** Setup for unload. */ signal(SIGTERM, UnloadAppRoutine); /************************************************************************** ** Hog the CPU. */ while (count) { count += 1; if (count == 5000000) { printf("\ncount = %d", count);" ThreadSwitchWithDelay(); delay(5000); count = 1; } } return; /* We will never get here. */ }
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.