mux/src/cque.cpp

Go to the documentation of this file.
00001 // cque.cpp -- commands and functions for manipulating the command queue.
00002 //
00003 // $Id: cque.cpp,v 1.38 2006/11/04 00:22:04 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include <signal.h>
00015 
00016 #include "attrs.h"
00017 #include "command.h"
00018 #include "interface.h"
00019 #include "powers.h"
00020 
00021 bool break_called = false;
00022 
00023 static CLinearTimeDelta GetProcessorUsage(void)
00024 {
00025     CLinearTimeDelta ltd;
00026 #ifdef WIN32
00027     if (platform == VER_PLATFORM_WIN32_NT)
00028     {
00029         FILETIME ftCreate;
00030         FILETIME ftExit;
00031         FILETIME ftKernel;
00032         FILETIME ftUser;
00033         fpGetProcessTimes(hGameProcess, &ftCreate, &ftExit, &ftKernel, &ftUser);
00034         ltd.Set100ns(*(INT64 *)(&ftUser));
00035         return ltd;
00036     }
00037 #endif
00038 
00039 #if !defined(WIN32) && defined(HAVE_GETRUSAGE)
00040 
00041     struct rusage usage;
00042     getrusage(RUSAGE_SELF, &usage);
00043     ltd.SetTimeValueStruct(&usage.ru_utime);
00044     return ltd;
00045 
00046 #else
00047 
00048     // Either this Unix doesn't have getrusage or this is a
00049     // fall-through case for Win32.
00050     //
00051     CLinearTimeAbsolute ltaNow;
00052     ltaNow.GetLocal();
00053     ltd = ltaNow - mudstate.start_time;
00054     return ltd;
00055 
00056 #endif
00057 }
00058 
00059 // ---------------------------------------------------------------------------
00060 // add_to: Adjust an object's queue or semaphore count.
00061 //
00062 static int add_to(dbref executor, int am, int attrnum)
00063 {
00064     int aflags;
00065     dbref aowner;
00066 
00067     char *atr_gotten = atr_get(executor, attrnum, &aowner, &aflags);
00068     int num = mux_atol(atr_gotten);
00069     free_lbuf(atr_gotten);
00070     num += am;
00071 
00072     char buff[20];
00073     int nlen = 0;
00074     *buff = '\0';
00075     if (num)
00076     {
00077         nlen = mux_ltoa(num, buff);
00078     }
00079     atr_add_raw_LEN(executor, attrnum, buff, nlen);
00080     return num;
00081 }
00082 
00083 // This Task assumes that pEntry is already unlinked from any lists it may
00084 // have been related to.
00085 //
00086 static void Task_RunQueueEntry(void *pEntry, int iUnused)
00087 {
00088     UNUSED_PARAMETER(iUnused);
00089 
00090     BQUE *point = (BQUE *)pEntry;
00091     dbref executor = point->executor;
00092 
00093     if (  Good_obj(executor)
00094        && !Going(executor))
00095     {
00096         giveto(executor, mudconf.waitcost);
00097         mudstate.curr_enactor = point->enactor;
00098         mudstate.curr_executor = executor;
00099         a_Queue(Owner(executor), -1);
00100         point->executor = NOTHING;
00101         if (!Halted(executor))
00102         {
00103             // Load scratch args.
00104             //
00105             for (int i = 0; i < MAX_GLOBAL_REGS; i++)
00106             {
00107                 if (point->scr[i])
00108                 {
00109                     int n = strlen(point->scr[i]);
00110                     memcpy(mudstate.global_regs[i], point->scr[i], n+1);
00111                     mudstate.glob_reg_len[i] = n;
00112                 }
00113                 else
00114                 {
00115                     mudstate.global_regs[i][0] = '\0';
00116                     mudstate.glob_reg_len[i] = 0;
00117                 }
00118             }
00119 
00120             char *command = point->comm;
00121 
00122             mux_assert(!mudstate.inpipe);
00123             mux_assert(mudstate.pipe_nest_lev == 0);
00124             mux_assert(mudstate.poutobj == NOTHING);
00125             mux_assert(!mudstate.pout);
00126 
00127             break_called = false;
00128             while (  command
00129                   && !break_called)
00130             {
00131                 mux_assert(!mudstate.poutnew);
00132                 mux_assert(!mudstate.poutbufc);
00133 
00134                 char *cp = parse_to(&command, ';', 0);
00135 
00136                 if (  cp
00137                    && *cp)
00138                 {
00139                     // Will command be piped?
00140                     //
00141                     if (  command
00142                        && *command == '|'
00143                        && mudstate.pipe_nest_lev < mudconf.ntfy_nest_lim)
00144                     {
00145                         command++;
00146                         mudstate.pipe_nest_lev++;
00147                         mudstate.inpipe = true;
00148 
00149                         mudstate.poutnew  = alloc_lbuf("process_command.pipe");
00150                         mudstate.poutbufc = mudstate.poutnew;
00151                         mudstate.poutobj  = executor;
00152                     }
00153                     else
00154                     {
00155                         mudstate.inpipe = false;
00156                         mudstate.poutobj = NOTHING;
00157                     }
00158 
00159                     CLinearTimeAbsolute ltaBegin;
00160                     ltaBegin.GetUTC();
00161                     MuxAlarm.Set(mudconf.max_cmdsecs);
00162                     CLinearTimeDelta ltdUsageBegin = GetProcessorUsage();
00163 
00164                     char *log_cmdbuf = process_command(executor, point->caller,
00165                         point->enactor, false, cp, point->env, point->nargs);
00166 
00167                     CLinearTimeAbsolute ltaEnd;
00168                     ltaEnd.GetUTC();
00169                     if (MuxAlarm.bAlarmed)
00170                     {
00171                         notify(executor, "GAME: Expensive activity abbreviated.");
00172                         s_Flags(point->enactor, FLAG_WORD1, Flags(point->enactor) | HALT);
00173                         s_Flags(point->executor, FLAG_WORD1, Flags(point->executor) | HALT);
00174                         halt_que(point->enactor, NOTHING);
00175                         halt_que(executor, NOTHING);
00176                     }
00177                     MuxAlarm.Clear();
00178 
00179                     CLinearTimeDelta ltdUsageEnd = GetProcessorUsage();
00180                     CLinearTimeDelta ltd = ltdUsageEnd - ltdUsageBegin;
00181                     db[executor].cpu_time_used += ltd;
00182 
00183                     ltd = ltaEnd - ltaBegin;
00184                     if (ltd > mudconf.rpt_cmdsecs)
00185                     {
00186                         STARTLOG(LOG_PROBLEMS, "CMD", "CPU");
00187                         log_name_and_loc(executor);
00188                         char *logbuf = alloc_lbuf("do_top.LOG.cpu");
00189                         sprintf(logbuf, " queued command taking %s secs (enactor #%d): ",
00190                             ltd.ReturnSecondsString(4), point->enactor);
00191                         log_text(logbuf);
00192                         free_lbuf(logbuf);
00193                         log_text(log_cmdbuf);
00194                         ENDLOG;
00195                     }
00196                 }
00197 
00198                 // Transition %| value.
00199                 //
00200                 if (mudstate.pout)
00201                 {
00202                     free_lbuf(mudstate.pout);
00203                     mudstate.pout = NULL;
00204                 }
00205                 if (mudstate.poutnew)
00206                 {
00207                     *mudstate.poutbufc = '\0';
00208                     mudstate.pout = mudstate.poutnew;
00209                     mudstate.poutnew  = NULL;
00210                     mudstate.poutbufc = NULL;
00211                 }
00212             }
00213 
00214             // Clean up %| value.
00215             //
00216             if (mudstate.pout)
00217             {
00218                 free_lbuf(mudstate.pout);
00219                 mudstate.pout = NULL;
00220             }
00221             mudstate.pipe_nest_lev = 0;
00222             mudstate.inpipe = false;
00223             mudstate.poutobj = NOTHING;
00224         }
00225     }
00226     MEMFREE(point->text);
00227     point->text = NULL;
00228     free_qentry(point);
00229 
00230     for (int i = 0; i < MAX_GLOBAL_REGS; i++)
00231     {
00232         mudstate.global_regs[i][0] = '\0';
00233         mudstate.glob_reg_len[i] = 0;
00234     }
00235 }
00236 
00237 // ---------------------------------------------------------------------------
00238 // que_want: Do we want this queue entry?
00239 //
00240 static bool que_want(BQUE *entry, dbref ptarg, dbref otarg)
00241 {
00242     if (  ptarg != NOTHING
00243        && ptarg != Owner(entry->executor))
00244     {
00245         return false;
00246     }
00247     return (  otarg == NOTHING
00248            || otarg == entry->executor);
00249 }
00250 
00251 static void Task_SemaphoreTimeout(void *pExpired, int iUnused)
00252 {
00253     UNUSED_PARAMETER(iUnused);
00254 
00255     // A semaphore has timed out.
00256     //
00257     BQUE *point = (BQUE *)pExpired;
00258     add_to(point->sem, -1, point->attr);
00259     point->sem = NOTHING;
00260     Task_RunQueueEntry(point, 0);
00261 }
00262 
00263 #ifdef QUERY_SLAVE
00264 void Task_SQLTimeout(void *pExpired, int iUnused)
00265 {
00266     // A SQL Query has timed out.
00267     //
00268     BQUE *point = (BQUE *)pExpired;
00269     Task_RunQueueEntry(point, 0);
00270 }
00271 #endif // QUERY_SLAVE
00272 
00273 static dbref Halt_Player_Target;
00274 static dbref Halt_Object_Target;
00275 static int   Halt_Entries;
00276 static dbref Halt_Player_Run;
00277 static dbref Halt_Entries_Run;
00278 
00279 static int CallBack_HaltQueue(PTASK_RECORD p)
00280 {
00281     if (  p->fpTask == Task_RunQueueEntry
00282 #ifdef QUERY_SLAVE
00283        || p->fpTask == Task_SQLTimeout
00284 #endif // QUERY_SLAVE
00285        || p->fpTask == Task_SemaphoreTimeout)
00286     {
00287         // This is a @wait, timed Semaphore Task, or timed SQL Query.
00288         //
00289         BQUE *point = (BQUE *)(p->arg_voidptr);
00290         if (que_want(point, Halt_Player_Target, Halt_Object_Target))
00291         {
00292             // Accounting for pennies and queue quota.
00293             //
00294             dbref dbOwner = point->executor;
00295             if (!isPlayer(dbOwner))
00296             {
00297                 dbOwner = Owner(dbOwner);
00298             }
00299             if (dbOwner != Halt_Player_Run)
00300             {
00301                 if (Halt_Player_Run != NOTHING)
00302                 {
00303                     giveto(Halt_Player_Run, mudconf.waitcost * Halt_Entries_Run);
00304                     a_Queue(Halt_Player_Run, -Halt_Entries_Run);
00305                 }
00306                 Halt_Player_Run = dbOwner;
00307                 Halt_Entries_Run = 0;
00308             }
00309             Halt_Entries++;
00310             Halt_Entries_Run++;
00311             if (p->fpTask == Task_SemaphoreTimeout)
00312             {
00313                 add_to(point->sem, -1, point->attr);
00314             }
00315             MEMFREE(point->text);
00316             point->text = NULL;
00317             free_qentry(point);
00318             return IU_REMOVE_TASK;
00319         }
00320     }
00321     return IU_NEXT_TASK;
00322 }
00323 
00324 // ------------------------------------------------------------------
00325 //
00326 // halt_que: Remove all queued commands that match (executor, object).
00327 //
00328 // (NOTHING,  NOTHING)    matches all queue entries.
00329 // (NOTHING,  <object>)   matches only queue entries run from <object>.
00330 // (<executor>, NOTHING)  matches only queue entries owned by <executor>.
00331 // (<executor>, <object>) matches only queue entries run from <objects>
00332 //                        and owned by <executor>.
00333 //
00334 int halt_que(dbref executor, dbref object)
00335 {
00336     Halt_Player_Target = executor;
00337     Halt_Object_Target = object;
00338     Halt_Entries       = 0;
00339     Halt_Player_Run    = NOTHING;
00340     Halt_Entries_Run   = 0;
00341 
00342     // Process @wait, timed semaphores, and untimed semaphores.
00343     //
00344     scheduler.TraverseUnordered(CallBack_HaltQueue);
00345 
00346     if (Halt_Player_Run != NOTHING)
00347     {
00348         giveto(Halt_Player_Run, mudconf.waitcost * Halt_Entries_Run);
00349         a_Queue(Halt_Player_Run, -Halt_Entries_Run);
00350         Halt_Player_Run = NOTHING;
00351     }
00352     return Halt_Entries;
00353 }
00354 
00355 // ---------------------------------------------------------------------------
00356 // do_halt: Command interface to halt_que.
00357 //
00358 void do_halt(dbref executor, dbref caller, dbref enactor, int key, char *target)
00359 {
00360     UNUSED_PARAMETER(caller);
00361     UNUSED_PARAMETER(enactor);
00362 
00363     dbref executor_targ, obj_targ;
00364 
00365     if ((key & HALT_ALL) && !Can_Halt(executor))
00366     {
00367         notify(executor, NOPERM_MESSAGE);
00368         return;
00369     }
00370 
00371     // Figure out what to halt.
00372     //
00373     if (!target || !*target)
00374     {
00375         obj_targ = NOTHING;
00376         if (key & HALT_ALL)
00377         {
00378             executor_targ = NOTHING;
00379         }
00380         else
00381         {
00382             executor_targ = Owner(executor);
00383             if (!isPlayer(executor))
00384             {
00385                 obj_targ = executor;
00386             }
00387         }
00388     }
00389     else
00390     {
00391         if (Can_Halt(executor))
00392         {
00393             obj_targ = match_thing(executor, target);
00394         }
00395         else
00396         {
00397             obj_targ = match_controlled(executor, target);
00398         }
00399         if (!Good_obj(obj_targ))
00400         {
00401             return;
00402         }
00403         if (key & HALT_ALL)
00404         {
00405             notify(executor, "Can't specify a target and /all");
00406             return;
00407         }
00408         if (isPlayer(obj_targ))
00409         {
00410             executor_targ = obj_targ;
00411             obj_targ = NOTHING;
00412         }
00413         else
00414         {
00415             executor_targ = NOTHING;
00416         }
00417     }
00418 
00419     int numhalted = halt_que(executor_targ, obj_targ);
00420     if (Quiet(executor))
00421     {
00422         return;
00423     }
00424     notify(Owner(executor), tprintf("%d queue entr%s removed.", numhalted, numhalted == 1 ? "y" : "ies"));
00425 }
00426 
00427 static int Notify_Key;
00428 static int Notify_Num_Done;
00429 static int Notify_Num_Max;
00430 static int Notify_Sem;
00431 static int Notify_Attr;
00432 
00433 // NFY_DRAIN or NFY_NFYALL
00434 //
00435 static int CallBack_NotifySemaphoreDrainOrAll(PTASK_RECORD p)
00436 {
00437     if (p->fpTask == Task_SemaphoreTimeout)
00438     {
00439         // This represents a semaphore.
00440         //
00441         BQUE *point = (BQUE *)(p->arg_voidptr);
00442         if (  point->sem == Notify_Sem
00443            && (  point->attr == Notify_Attr
00444               || !Notify_Attr))
00445         {
00446             Notify_Num_Done++;
00447             if (Notify_Key == NFY_DRAIN)
00448             {
00449                 // Discard the command
00450                 //
00451                 giveto(point->executor, mudconf.waitcost);
00452                 a_Queue(Owner(point->executor), -1);
00453                 MEMFREE(point->text);
00454                 point->text = NULL;
00455                 free_qentry(point);
00456                 return IU_REMOVE_TASK;
00457             }
00458             else
00459             {
00460                 // Allow the command to run. The priority may have been
00461                 // PRIORITY_SUSPEND, so we need to change it.
00462                 //
00463                 if (isPlayer(point->enactor))
00464                 {
00465                     p->iPriority = PRIORITY_PLAYER;
00466                 }
00467                 else
00468                 {
00469                     p->iPriority = PRIORITY_OBJECT;
00470                 }
00471                 p->ltaWhen.GetUTC();
00472                 p->fpTask = Task_RunQueueEntry;
00473                 return IU_UPDATE_TASK;
00474             }
00475         }
00476     }
00477     return IU_NEXT_TASK;
00478 }
00479 
00480 // NFY_NFY or NFY_QUIET
00481 //
00482 static int CallBack_NotifySemaphoreFirstOrQuiet(PTASK_RECORD p)
00483 {
00484     // If we've notified enough, exit.
00485     //
00486     if (  Notify_Key == NFY_NFY
00487        && Notify_Num_Done >= Notify_Num_Max)
00488     {
00489         return IU_DONE;
00490     }
00491 
00492     if (p->fpTask == Task_SemaphoreTimeout)
00493     {
00494         // This represents a semaphore.
00495         //
00496         BQUE *point = (BQUE *)(p->arg_voidptr);
00497         if (  point->sem == Notify_Sem
00498            && (  point->attr == Notify_Attr
00499               || !Notify_Attr))
00500         {
00501             Notify_Num_Done++;
00502 
00503             // Allow the command to run. The priority may have been
00504             // PRIORITY_SUSPEND, so we need to change it.
00505             //
00506             if (isPlayer(point->enactor))
00507             {
00508                 p->iPriority = PRIORITY_PLAYER;
00509             }
00510             else
00511             {
00512                 p->iPriority = PRIORITY_OBJECT;
00513             }
00514             p->ltaWhen.GetUTC();
00515             p->fpTask = Task_RunQueueEntry;
00516             return IU_UPDATE_TASK;
00517         }
00518     }
00519     return IU_NEXT_TASK;
00520 }
00521 
00522 // ---------------------------------------------------------------------------
00523 // nfy_que: Notify commands from the queue and perform or discard them.
00524 
00525 int nfy_que(dbref sem, int attr, int key, int count)
00526 {
00527     int cSemaphore = 1;
00528     if (attr)
00529     {
00530         int   aflags;
00531         dbref aowner;
00532         char *str = atr_get(sem, attr, &aowner, &aflags);
00533         cSemaphore = mux_atol(str);
00534         free_lbuf(str);
00535     }
00536 
00537     Notify_Num_Done = 0;
00538     if (cSemaphore > 0)
00539     {
00540         Notify_Key     = key;
00541         Notify_Sem     = sem;
00542         Notify_Attr    = attr;
00543         Notify_Num_Max = count;
00544         if (  key == NFY_NFY
00545            || key == NFY_QUIET)
00546         {
00547             scheduler.TraverseOrdered(CallBack_NotifySemaphoreFirstOrQuiet);
00548         }
00549         else
00550         {
00551             scheduler.TraverseUnordered(CallBack_NotifySemaphoreDrainOrAll);
00552         }
00553     }
00554 
00555     // Update the sem waiters count.
00556     //
00557     if (key == NFY_NFY)
00558     {
00559         add_to(sem, -count, attr);
00560     }
00561     else
00562     {
00563         atr_clr(sem, attr);
00564     }
00565 
00566     return Notify_Num_Done;
00567 }
00568 
00569 // ---------------------------------------------------------------------------
00570 // do_notify: Command interface to nfy_que
00571 
00572 void do_notify
00573 (
00574     dbref executor,
00575     dbref caller,
00576     dbref enactor,
00577     int   key,
00578     int   nargs,
00579     char *what,
00580     char *count
00581 )
00582 {
00583     UNUSED_PARAMETER(caller);
00584     UNUSED_PARAMETER(enactor);
00585     UNUSED_PARAMETER(nargs);
00586 
00587     char *obj = parse_to(&what, '/', 0);
00588     init_match(executor, obj, NOTYPE);
00589     match_everything(0);
00590 
00591     dbref thing = noisy_match_result();
00592     if (!Good_obj(thing))
00593     {
00594         return;
00595     }
00596     if (!Controls(executor, thing) && !Link_ok(thing))
00597     {
00598         notify(executor, NOPERM_MESSAGE);
00599     }
00600     else
00601     {
00602         int atr = A_SEMAPHORE;
00603         if (  what
00604            && what[0] != '\0')
00605         {
00606             int i = mkattr(executor, what);
00607             if (0 < i)
00608             {
00609                 atr = i;
00610                 if (atr != A_SEMAPHORE)
00611                 {
00612                     // Do they have permission to set this attribute?
00613                     //
00614                     ATTR *ap = (ATTR *)anum_get(atr);
00615                     if (!bCanSetAttr(executor, thing, ap))
00616                     {
00617                         notify_quiet(executor, NOPERM_MESSAGE);
00618                         return;
00619                     }
00620                 }
00621             }
00622         }
00623 
00624         int loccount;
00625         if (  count
00626            && count[0] != '\0')
00627         {
00628             loccount = mux_atol(count);
00629         }
00630         else
00631         {
00632             loccount = 1;
00633         }
00634         if (loccount > 0)
00635         {
00636             nfy_que(thing, atr, key, loccount);
00637             if (  (!(Quiet(executor) || Quiet(thing)))
00638                && key != NFY_QUIET)
00639             {
00640                 if (key == NFY_DRAIN)
00641                 {
00642                     notify_quiet(executor, "Drained.");
00643                 }
00644                 else
00645                 {
00646                     notify_quiet(executor, "Notified.");
00647                 }
00648             }
00649         }
00650     }
00651 }
00652 
00653 // ---------------------------------------------------------------------------
00654 // setup_que: Set up a queue entry.
00655 //
00656 static BQUE *setup_que(dbref executor, dbref caller, dbref enactor,
00657                        char *command, char *args[], int nargs, char *sargs[])
00658 {
00659     int a;
00660     BQUE *tmp;
00661 
00662     // Can we run commands at all?
00663     //
00664     if (Halted(executor))
00665         return NULL;
00666 
00667     // Make sure executor can afford to do it.
00668     //
00669     a = mudconf.waitcost;
00670     if (mudconf.machinecost && RandomINT32(0, mudconf.machinecost-1) == 0)
00671     {
00672         a++;
00673     }
00674     if (!payfor(executor, a))
00675     {
00676         notify(Owner(executor), "Not enough money to queue command.");
00677         return NULL;
00678     }
00679 
00680     // Wizards and their objs may queue up to db_top+1 cmds. Players are
00681     // limited to QUEUE_QUOTA. -mnp
00682     //
00683     a = QueueMax(Owner(executor));
00684     if (a_Queue(Owner(executor), 1) > a)
00685     {
00686         a_Queue(Owner(executor), -1);
00687 
00688         notify(Owner(executor),
00689             "Run away objects: too many commands queued.  Halted.");
00690         halt_que(Owner(executor), NOTHING);
00691 
00692         // Halt also means no command execution allowed.
00693         //
00694         s_Halted(executor);
00695         return NULL;
00696     }
00697 
00698     // We passed all the tests.
00699     //
00700 
00701     // Calculate the length of the save string.
00702     //
00703     unsigned int tlen = 0;
00704     static unsigned int nCommand;
00705     static unsigned int nLenEnv[NUM_ENV_VARS];
00706     static unsigned int nLenRegs[MAX_GLOBAL_REGS];
00707 
00708     if (command)
00709     {
00710         nCommand = strlen(command) + 1;
00711         tlen = nCommand;
00712     }
00713     if (nargs > NUM_ENV_VARS)
00714     {
00715         nargs = NUM_ENV_VARS;
00716     }
00717     for (a = 0; a < nargs; a++)
00718     {
00719         if (args[a])
00720         {
00721             nLenEnv[a] = strlen(args[a]) + 1;
00722             tlen += nLenEnv[a];
00723         }
00724     }
00725     if (sargs)
00726     {
00727         for (a = 0; a < MAX_GLOBAL_REGS; a++)
00728         {
00729             if (sargs[a])
00730             {
00731                 nLenRegs[a] = strlen(sargs[a]) + 1;
00732                 tlen += nLenRegs[a];
00733             }
00734         }
00735     }
00736 
00737     // Create the qeue entry and load the save string.
00738     //
00739     tmp = alloc_qentry("setup_que.qblock");
00740     tmp->comm = NULL;
00741 
00742     char *tptr = tmp->text = (char *)MEMALLOC(tlen);
00743     ISOUTOFMEMORY(tptr);
00744 
00745     if (command)
00746     {
00747         memcpy(tptr, command, nCommand);
00748         tmp->comm = tptr;
00749         tptr += nCommand;
00750     }
00751     for (a = 0; a < nargs; a++)
00752     {
00753         if (args[a])
00754         {
00755             memcpy(tptr, args[a], nLenEnv[a]);
00756             tmp->env[a] = tptr;
00757             tptr += nLenEnv[a];
00758         }
00759         else
00760         {
00761             tmp->env[a] = NULL;
00762         }
00763     }
00764     for ( ; a < NUM_ENV_VARS; a++)
00765     {
00766         tmp->env[a] = NULL;
00767     }
00768     for (a = 0; a < MAX_GLOBAL_REGS; a++)
00769     {
00770         tmp->scr[a] = NULL;
00771     }
00772     if (sargs)
00773     {
00774         for (a = 0; a < MAX_GLOBAL_REGS; a++)
00775         {
00776             if (sargs[a])
00777             {
00778                 memcpy(tptr, sargs[a], nLenRegs[a]);
00779                 tmp->scr[a] = tptr;
00780                 tptr += nLenRegs[a];
00781             }
00782         }
00783     }
00784 
00785     // Load the rest of the queue block.
00786     //
00787     tmp->executor = executor;
00788     tmp->IsTimed = false;
00789     tmp->sem = NOTHING;
00790     tmp->attr = 0;
00791     tmp->enactor = enactor;
00792     tmp->caller = caller;
00793     tmp->nargs = nargs;
00794     return tmp;
00795 }
00796 
00797 // ---------------------------------------------------------------------------
00798 // wait_que: Add commands to the wait or semaphore queues.
00799 //
00800 void wait_que
00801 (
00802     dbref executor,
00803     dbref caller,
00804     dbref enactor,
00805     bool bTimed,
00806     CLinearTimeAbsolute &ltaWhen,
00807     dbref sem,
00808     int   attr,
00809     char *command,
00810     char *args[],
00811     int   nargs,
00812     char *sargs[]
00813 )
00814 {
00815     if (!(mudconf.control_flags & CF_INTERP))
00816     {
00817         return;
00818     }
00819 
00820     BQUE *tmp = setup_que(executor, caller, enactor, command, args, nargs, sargs);
00821     if (!tmp)
00822     {
00823         return;
00824     }
00825 
00826     int iPriority;
00827     if (isPlayer(tmp->enactor))
00828     {
00829         iPriority = PRIORITY_PLAYER;
00830     }
00831     else
00832     {
00833         iPriority = PRIORITY_OBJECT;
00834     }
00835 
00836     tmp->IsTimed = bTimed;
00837     tmp->waittime = ltaWhen;
00838     tmp->sem = sem;
00839     tmp->attr = attr;
00840 
00841     if (sem == NOTHING)
00842     {
00843         // Not a semaphore, so let it run it immediately or put it on
00844         // the wait queue.
00845         //
00846         if (tmp->IsTimed)
00847         {
00848             scheduler.DeferTask(tmp->waittime, iPriority, Task_RunQueueEntry, tmp, 0);
00849         }
00850         else
00851         {
00852             scheduler.DeferImmediateTask(iPriority, Task_RunQueueEntry, tmp, 0);
00853         }
00854     }
00855     else
00856     {
00857         if (!tmp->IsTimed)
00858         {
00859             // In this case, the timeout task below will never run,
00860             // but it allows us to manage all semaphores together in
00861             // the same data structure.
00862             //
00863             iPriority = PRIORITY_SUSPEND;
00864         }
00865         scheduler.DeferTask(tmp->waittime, iPriority, Task_SemaphoreTimeout, tmp, 0);
00866     }
00867 }
00868 
00869 #ifdef QUERY_SLAVE
00870 // ---------------------------------------------------------------------------
00871 // sql_que: Add commands to the sql queue.
00872 //
00873 void sql_que
00874 (
00875     dbref executor,
00876     dbref caller,
00877     dbref enactor,
00878     bool bTimed,
00879     CLinearTimeAbsolute &ltaWhen,
00880     dbref thing,
00881     int   attr,
00882     char *command,
00883     char *args[],
00884     int   nargs,
00885     char *sargs[]
00886 )
00887 {
00888     if (!(mudconf.control_flags & CF_INTERP))
00889     {
00890         return;
00891     }
00892 
00893     BQUE *tmp = setup_que(executor, caller, enactor, command, args, nargs, sargs);
00894     if (!tmp)
00895     {
00896         return;
00897     }
00898 
00899     tmp->IsTimed = bTimed;
00900     tmp->waittime = ltaWhen;
00901     tmp->sem = thing;
00902     tmp->attr = attr;
00903 
00904     int iPriority;
00905     if (!tmp->IsTimed)
00906     {
00907         // In this case, the timeout task below will never run,
00908         // but it allows us to manage all semaphores together in
00909         // the same data structure.
00910         //
00911         iPriority = PRIORITY_SUSPEND;
00912     }
00913     else
00914     {
00915         iPriority = PRIORITY_OBJECT;
00916     }
00917     scheduler.DeferTask(tmp->waittime, iPriority, Task_SQLTimeout, tmp, 0);
00918 }
00919 #endif // QUERY_SLAVE
00920 
00921 // ---------------------------------------------------------------------------
00922 // do_wait: Command interface to wait_que
00923 //
00924 void do_wait
00925 (
00926     dbref executor,
00927     dbref caller,
00928     dbref enactor,
00929     int key,
00930     char *event,
00931     char *cmd,
00932     char *cargs[],
00933     int ncargs
00934 )
00935 {
00936     CLinearTimeAbsolute ltaWhen;
00937     CLinearTimeDelta    ltd;
00938 
00939     // If arg1 is all numeric, do simple (non-sem) timed wait.
00940     //
00941     if (is_rational(event))
00942     {
00943         if (key & WAIT_UNTIL)
00944         {
00945             ltaWhen.SetSecondsString(event);
00946         }
00947         else
00948         {
00949             ltaWhen.GetUTC();
00950             ltd.SetSecondsString(event);
00951             ltaWhen += ltd;
00952         }
00953         wait_que(executor, caller, enactor, true, ltaWhen, NOTHING, 0, cmd,
00954             cargs, ncargs, mudstate.global_regs);
00955         return;
00956     }
00957 
00958     // Semaphore wait with optional timeout.
00959     //
00960     char *what = parse_to(&event, '/', 0);
00961     init_match(executor, what, NOTYPE);
00962     match_everything(0);
00963 
00964     dbref thing = noisy_match_result();
00965     if (!Good_obj(thing))
00966     {
00967         return;
00968     }
00969     else if (!Controls(executor, thing) && !Link_ok(thing))
00970     {
00971         notify(executor, NOPERM_MESSAGE);
00972     }
00973     else
00974     {
00975         // Get timeout, default 0.
00976         //
00977         int atr = A_SEMAPHORE;
00978         bool bTimed = false;
00979         if (event && *event)
00980         {
00981             if (is_rational(event))
00982             {
00983                 if (key & WAIT_UNTIL)
00984                 {
00985                     ltaWhen.SetSecondsString(event);
00986                 }
00987                 else
00988                 {
00989                     ltaWhen.GetUTC();
00990                     ltd.SetSecondsString(event);
00991                     ltaWhen += ltd;
00992                 }
00993                 bTimed = true;
00994             }
00995             else
00996             {
00997                 ATTR *ap = atr_str(event);
00998                 if (!ap)
00999                 {
01000                     atr = mkattr(executor, event);
01001                     if (atr <= 0)
01002                     {
01003                         notify_quiet(executor, "Invalid attribute.");
01004                         return;
01005                     }
01006                     ap = atr_num(atr);
01007                 }
01008                 else
01009                 {
01010                     atr = ap->number;
01011                 }
01012                 if (!bCanSetAttr(executor, thing, ap))
01013                 {
01014                     notify_quiet(executor, NOPERM_MESSAGE);
01015                     return;
01016                 }
01017             }
01018         }
01019 
01020         int num = add_to(thing, 1, atr);
01021         if (num <= 0)
01022         {
01023             // Thing over-notified, run the command immediately.
01024             //
01025             thing = NOTHING;
01026             bTimed = false;
01027         }
01028         wait_que(executor, caller, enactor, bTimed, ltaWhen, thing, atr,
01029             cmd, cargs, ncargs, mudstate.global_regs);
01030     }
01031 }
01032 
01033 #ifdef QUERY_SLAVE
01034 // ---------------------------------------------------------------------------
01035 // do_query: Command interface to sql_que
01036 //
01037 void do_query
01038 (
01039     dbref executor,
01040     dbref caller,
01041     dbref enactor,
01042     int   key,
01043     char *dbref_attr,
01044     char *dbname_query,
01045     char *cargs[],
01046     int   ncargs
01047 )
01048 {
01049     if (key & QUERY_SQL)
01050     {
01051         // SQL Query.
01052         //
01053         dbref thing;
01054         ATTR *pattr;
01055 
01056         if (!( parse_attrib(executor, dbref_attr, &thing, &pattr)
01057             && pattr))
01058         {
01059             notify_quiet(executor, "No match.");
01060             return;
01061         }
01062 
01063         if (!Controls(executor, thing))
01064         {
01065             notify_quiet(executor, NOPERM_MESSAGE);
01066             return;
01067         }
01068 
01069         char *pQuery = dbname_query;
01070         char *pDBName = parse_to(&pQuery, '/', 0);
01071 
01072         if (NULL == pQuery)
01073         {
01074             notify(executor, "QUERY: No Query.");
01075             return;
01076         }
01077 
01078         STARTLOG(LOG_ALWAYS, "CMD", "QUERY");
01079         Log.tinyprintf("Thing=#%d, Attr=%s, dbname=%s, query=%s", thing, pattr->name, pDBName, pQuery);
01080         ENDLOG;
01081     }
01082     else
01083     {
01084         notify_quiet(executor, "At least one query option is required.");
01085     }
01086 }
01087 #endif // QUERY_SLAVE
01088 
01089 static CLinearTimeAbsolute Show_lsaNow;
01090 static int Total_SystemTasks;
01091 static int Total_RunQueueEntry;
01092 static int Shown_RunQueueEntry;
01093 static int Total_SemaphoreTimeout;
01094 static int Shown_SemaphoreTimeout;
01095 static dbref Show_Player_Target;
01096 static dbref Show_Object_Target;
01097 static int Show_Key;
01098 static dbref Show_Player;
01099 static int Show_bFirstLine;
01100 
01101 #ifdef QUERY_SLAVE
01102 int Total_SQLTimeout;
01103 int Shown_SQLTimeout;
01104 #endif // QUERY_SLAVE
01105 
01106 static int CallBack_ShowDispatches(PTASK_RECORD p)
01107 {
01108     Total_SystemTasks++;
01109     CLinearTimeDelta ltd = p->ltaWhen - Show_lsaNow;
01110     if (p->fpTask == dispatch_DatabaseDump)
01111     {
01112         notify(Show_Player, tprintf("[%d]auto-@dump", ltd.ReturnSeconds()));
01113     }
01114     else if (p->fpTask == dispatch_FreeListReconstruction)
01115     {
01116         notify(Show_Player, tprintf("[%d]auto-@dbck", ltd.ReturnSeconds()));
01117     }
01118     else if (p->fpTask == dispatch_IdleCheck)
01119     {
01120         notify(Show_Player, tprintf("[%d]Check for idle players", ltd.ReturnSeconds()));
01121     }
01122     else if (p->fpTask == dispatch_CheckEvents)
01123     {
01124         notify(Show_Player, tprintf("[%d]Test for @daily time", ltd.ReturnSeconds()));
01125     }
01126 #ifndef MEMORY_BASED
01127     else if (p->fpTask == dispatch_CacheTick)
01128     {
01129         notify(Show_Player, tprintf("[%d]Database cache tick", ltd.ReturnSeconds()));
01130     }
01131 #endif
01132     else if (p->fpTask == Task_ProcessCommand)
01133     {
01134         notify(Show_Player, tprintf("[%d]Further command quota", ltd.ReturnSeconds()));
01135     }
01136 #ifdef WIN32
01137     else if (p->fpTask == Task_FreeDescriptor)
01138     {
01139         notify(Show_Player, tprintf("[%d]Delayed descriptor deallocation", ltd.ReturnSeconds()));
01140     }
01141     else if (p->fpTask == Task_DeferredClose)
01142     {
01143         notify(Show_Player, tprintf("[%d]Delayed socket close", ltd.ReturnSeconds()));
01144     }
01145 #endif
01146     else
01147     {
01148         Total_SystemTasks--;
01149     }
01150     return IU_NEXT_TASK;
01151 }
01152 
01153 static void ShowPsLine(BQUE *tmp)
01154 {
01155     char *bufp = unparse_object(Show_Player, tmp->executor, false);
01156     if (tmp->IsTimed && (Good_obj(tmp->sem)))
01157     {
01158         CLinearTimeDelta ltd = tmp->waittime - Show_lsaNow;
01159         notify(Show_Player, tprintf("[#%d/%d]%s:%s", tmp->sem, ltd.ReturnSeconds(), bufp, tmp->comm));
01160     }
01161     else if (tmp->IsTimed)
01162     {
01163         CLinearTimeDelta ltd = tmp->waittime - Show_lsaNow;
01164         notify(Show_Player, tprintf("[%d]%s:%s", ltd.ReturnSeconds(), bufp, tmp->comm));
01165     }
01166     else if (Good_obj(tmp->sem))
01167     {
01168         notify(Show_Player, tprintf("[#%d]%s:%s", tmp->sem, bufp, tmp->comm));
01169     }
01170     else
01171     {
01172         notify(Show_Player, tprintf("%s:%s", bufp, tmp->comm));
01173     }
01174     char *bp = bufp;
01175     if (Show_Key == PS_LONG)
01176     {
01177         for (int i = 0; i < tmp->nargs; i++)
01178         {
01179             if (tmp->env[i] != NULL)
01180             {
01181                 safe_str("; Arg", bufp, &bp);
01182                 safe_chr((char)(i + '0'), bufp, &bp);
01183                 safe_str("='", bufp, &bp);
01184                 safe_str(tmp->env[i], bufp, &bp);
01185                 safe_chr('\'', bufp, &bp);
01186             }
01187         }
01188         *bp = '\0';
01189         bp = unparse_object(Show_Player, tmp->enactor, false);
01190         notify(Show_Player, tprintf("   Enactor: %s%s", bp, bufp));
01191         free_lbuf(bp);
01192     }
01193     free_lbuf(bufp);
01194 }
01195 
01196 static int CallBack_ShowWait(PTASK_RECORD p)
01197 {
01198     if (p->fpTask != Task_RunQueueEntry)
01199     {
01200         return IU_NEXT_TASK;
01201     }
01202 
01203     Total_RunQueueEntry++;
01204     BQUE *tmp = (BQUE *)(p->arg_voidptr);
01205     if (que_want(tmp, Show_Player_Target, Show_Object_Target))
01206     {
01207         Shown_RunQueueEntry++;
01208         if (Show_Key == PS_SUMM)
01209         {
01210             return IU_NEXT_TASK;
01211         }
01212         if (Show_bFirstLine)
01213         {
01214             notify(Show_Player, "----- Wait Queue -----");
01215             Show_bFirstLine = false;
01216         }
01217         ShowPsLine(tmp);
01218     }
01219     return IU_NEXT_TASK;
01220 }
01221 
01222 static int CallBack_ShowSemaphore(PTASK_RECORD p)
01223 {
01224     if (p->fpTask != Task_SemaphoreTimeout)
01225     {
01226         return IU_NEXT_TASK;
01227     }
01228 
01229     Total_SemaphoreTimeout++;
01230     BQUE *tmp = (BQUE *)(p->arg_voidptr);
01231     if (que_want(tmp, Show_Player_Target, Show_Object_Target))
01232     {
01233         Shown_SemaphoreTimeout++;
01234         if (Show_Key == PS_SUMM)
01235         {
01236             return IU_NEXT_TASK;
01237         }
01238         if (Show_bFirstLine)
01239         {
01240             notify(Show_Player, "----- Semaphore Queue -----");
01241             Show_bFirstLine = false;
01242         }
01243         ShowPsLine(tmp);
01244     }
01245     return IU_NEXT_TASK;
01246 }
01247 
01248 #ifdef QUERY_SLAVE
01249 int CallBack_ShowSQLQueries(PTASK_RECORD p)
01250 {
01251     if (p->fpTask != Task_SQLTimeout)
01252     {
01253         return IU_NEXT_TASK;
01254     }
01255 
01256     Total_SQLTimeout++;
01257     BQUE *tmp = (BQUE *)(p->arg_voidptr);
01258     if (que_want(tmp, Show_Player_Target, Show_Object_Target))
01259     {
01260         Shown_SQLTimeout++;
01261         if (Show_Key == PS_SUMM)
01262         {
01263             return IU_NEXT_TASK;
01264         }
01265         if (Show_bFirstLine)
01266         {
01267             notify(Show_Player, "----- SQL Queries -----");
01268             Show_bFirstLine = false;
01269         }
01270         ShowPsLine(tmp);
01271     }
01272     return IU_NEXT_TASK;
01273 }
01274 #endif
01275 
01276 // ---------------------------------------------------------------------------
01277 // do_ps: tell executor what commands they have pending in the queue
01278 //
01279 void do_ps(dbref executor, dbref caller, dbref enactor, int key, char *target)
01280 {
01281     UNUSED_PARAMETER(caller);
01282     UNUSED_PARAMETER(enactor);
01283 
01284     char *bufp;
01285     dbref executor_targ, obj_targ;
01286 
01287     // Figure out what to list the queue for.
01288     //
01289     if ((key & PS_ALL) && !See_Queue(executor))
01290     {
01291         notify(executor, NOPERM_MESSAGE);
01292         return;
01293     }
01294     if (!target || !*target)
01295     {
01296         obj_targ = NOTHING;
01297         if (key & PS_ALL)
01298         {
01299             executor_targ = NOTHING;
01300         }
01301         else
01302         {
01303             executor_targ = Owner(executor);
01304             if (!isPlayer(executor))
01305             {
01306                 obj_targ = executor;
01307             }
01308         }
01309     }
01310     else
01311     {
01312         executor_targ = Owner(executor);
01313         obj_targ = match_controlled(executor, target);
01314         if (obj_targ == NOTHING)
01315         {
01316             return;
01317         }
01318         if (key & PS_ALL)
01319         {
01320             notify(executor, "Can't specify a target and /all");
01321             return;
01322         }
01323         if (isPlayer(obj_targ))
01324         {
01325             executor_targ = obj_targ;
01326             obj_targ = NOTHING;
01327         }
01328     }
01329     key = key & ~PS_ALL;
01330 
01331     switch (key)
01332     {
01333     case PS_BRIEF:
01334     case PS_SUMM:
01335     case PS_LONG:
01336         break;
01337 
01338     default:
01339         notify(executor, "Illegal combination of switches.");
01340         return;
01341     }
01342 
01343     Show_lsaNow.GetUTC();
01344     Total_SystemTasks = 0;
01345     Total_RunQueueEntry = 0;
01346     Shown_RunQueueEntry = 0;
01347     Total_SemaphoreTimeout = 0;
01348     Shown_SemaphoreTimeout = 0;
01349     Show_Player_Target = executor_targ;
01350     Show_Object_Target = obj_targ;
01351     Show_Key = key;
01352     Show_Player = executor;
01353     Show_bFirstLine = true;
01354     scheduler.TraverseOrdered(CallBack_ShowWait);
01355     Show_bFirstLine = true;
01356     scheduler.TraverseOrdered(CallBack_ShowSemaphore);
01357 #ifdef QUERY_SLAVE
01358     Show_bFirstLine = true;
01359     scheduler.TraverseOrdered(CallBack_ShowSQLQueries);
01360 #endif // QUERY_SLAVE
01361     if (Wizard(executor))
01362     {
01363         notify(executor, "----- System Queue -----");
01364         scheduler.TraverseOrdered(CallBack_ShowDispatches);
01365     }
01366 
01367     // Display stats.
01368     //
01369     bufp = alloc_mbuf("do_ps");
01370 #ifdef QUERY_SLAVE
01371     sprintf(bufp, "Totals: Wait Queue...%d/%d  Semaphores...%d/%d  SQL %d/%d",
01372         Shown_RunQueueEntry, Total_RunQueueEntry,
01373         Shown_SemaphoreTimeout, Total_SemaphoreTimeout,
01374         Shown_SQLTimeout, Total_SQLTimeout);
01375 #else
01376     sprintf(bufp, "Totals: Wait Queue...%d/%d  Semaphores...%d/%d",
01377         Shown_RunQueueEntry, Total_RunQueueEntry,
01378         Shown_SemaphoreTimeout, Total_SemaphoreTimeout);
01379 #endif // QUERY_SLAVE
01380     notify(executor, bufp);
01381     if (Wizard(executor))
01382     {
01383         sprintf(bufp, "        System Tasks.....%d", Total_SystemTasks);
01384         notify(executor, bufp);
01385     }
01386     free_mbuf(bufp);
01387 }
01388 
01389 static CLinearTimeDelta ltdWarp;
01390 static int CallBack_Warp(PTASK_RECORD p)
01391 {
01392     if (  p->fpTask == Task_RunQueueEntry
01393 #ifdef QUERY_SLAVE
01394        || p->fpTask == Task_SQLTimeout
01395 #endif // QUERY_SLAVE
01396        || p->fpTask == Task_SemaphoreTimeout)
01397     {
01398         BQUE *point = (BQUE *)(p->arg_voidptr);
01399         if (point->IsTimed)
01400         {
01401             point->waittime -= ltdWarp;
01402             p->ltaWhen -= ltdWarp;
01403             return IU_UPDATE_TASK;
01404         }
01405     }
01406     return IU_NEXT_TASK;
01407 }
01408 
01409 // ---------------------------------------------------------------------------
01410 // do_queue: Queue management
01411 //
01412 void do_queue(dbref executor, dbref caller, dbref enactor, int key, char *arg)
01413 {
01414     UNUSED_PARAMETER(caller);
01415     UNUSED_PARAMETER(enactor);
01416 
01417     if (key == QUEUE_KICK)
01418     {
01419         int i = mux_atol(arg);
01420         int save_minPriority = scheduler.GetMinPriority();
01421         if (save_minPriority <= PRIORITY_CF_DEQUEUE_DISABLED)
01422         {
01423             notify(executor, "Warning: automatic dequeueing is disabled.");
01424             scheduler.SetMinPriority(PRIORITY_CF_DEQUEUE_ENABLED);
01425         }
01426         CLinearTimeAbsolute lsaNow;
01427         lsaNow.GetUTC();
01428         scheduler.ReadyTasks(lsaNow);
01429         int ncmds = scheduler.RunTasks(i);
01430         scheduler.SetMinPriority(save_minPriority);
01431 
01432         if (!Quiet(executor))
01433         {
01434             notify(executor, tprintf("%d commands processed.", ncmds));
01435         }
01436     }
01437     else if (key == QUEUE_WARP)
01438     {
01439         int iWarp = mux_atol(arg);
01440         ltdWarp.SetSeconds(iWarp);
01441         if (scheduler.GetMinPriority() <= PRIORITY_CF_DEQUEUE_DISABLED)
01442         {
01443             notify(executor, "Warning: automatic dequeueing is disabled.");
01444         }
01445 
01446         scheduler.TraverseUnordered(CallBack_Warp);
01447 
01448         if (Quiet(executor))
01449         {
01450             return;
01451         }
01452         if (iWarp > 0)
01453         {
01454             notify(executor, tprintf("WaitQ timer advanced %d seconds.", iWarp));
01455         }
01456         else if (iWarp < 0)
01457         {
01458             notify(executor, tprintf("WaitQ timer set back %d seconds.", iWarp));
01459         }
01460         else
01461         {
01462             notify(executor, "Object queue appended to player queue.");
01463         }
01464     }
01465 }

Generated on Mon May 28 04:40:08 2007 for MUX by  doxygen 1.4.7