00001
00002
00003
00004
00005
00006
00007
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
00049
00050
00051 CLinearTimeAbsolute ltaNow;
00052 ltaNow.GetLocal();
00053 ltd = ltaNow - mudstate.start_time;
00054 return ltd;
00055
00056 #endif
00057 }
00058
00059
00060
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
00084
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
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
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
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
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
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
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
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
00285 || p->fpTask == Task_SemaphoreTimeout)
00286 {
00287
00288
00289 BQUE *point = (BQUE *)(p->arg_voidptr);
00290 if (que_want(point, Halt_Player_Target, Halt_Object_Target))
00291 {
00292
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
00327
00328
00329
00330
00331
00332
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
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
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
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
00434
00435 static int CallBack_NotifySemaphoreDrainOrAll(PTASK_RECORD p)
00436 {
00437 if (p->fpTask == Task_SemaphoreTimeout)
00438 {
00439
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
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
00461
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
00481
00482 static int CallBack_NotifySemaphoreFirstOrQuiet(PTASK_RECORD p)
00483 {
00484
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
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
00504
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
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
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
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
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
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
00663
00664 if (Halted(executor))
00665 return NULL;
00666
00667
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
00681
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
00693
00694 s_Halted(executor);
00695 return NULL;
00696 }
00697
00698
00699
00700
00701
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
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
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
00799
00800 void wait_que
00801 (
00802 dbref executor,
00803 dbref caller,
00804 dbref enactor,
00805 bool bTimed,
00806 CLinearTimeAbsolute <aWhen,
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
00844
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
00860
00861
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
00872
00873 void sql_que
00874 (
00875 dbref executor,
00876 dbref caller,
00877 dbref enactor,
00878 bool bTimed,
00879 CLinearTimeAbsolute <aWhen,
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
00908
00909
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
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
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
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
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
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
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
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
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
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
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
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
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 }