35
\$\begingroup\$

Write a program that starts itself again when finishes.

There should be no more than one instance of the program running at same time. Not even for a slightest moment of time.

You can ignore any instance that is manually started by user during your cycle. But your code should not do it in your restart cycle.

Program can start after any amount of time, as long as it is guaranteed that it starts again.

The only way to stop the cycle is to kill the process.

Your solution should not involve restarting of the environment (in which program is running, includes OS, machine, VM, shell etc). Only your program is allowed to restart.

\$\endgroup\$
14
  • 11
    \$\begingroup\$ Isn't this just what exec does in linux? \$\endgroup\$
    – mniip
    Feb 21, 2014 at 15:41
  • 11
    \$\begingroup\$ I'm a little lazy to write it right now, but my submission would be(for windows): "Edit the registry so that my program boots on startup. Run shutdown -r -t 0 -f". \$\endgroup\$
    – Cruncher
    Feb 21, 2014 at 15:48
  • 3
    \$\begingroup\$ Killing the process won't kill your cycle though. \$\endgroup\$
    – microbian
    Feb 21, 2014 at 15:49
  • 19
    \$\begingroup\$ I just realized: if I want to write a virus and don't know how, I could 1) go to StackOverflow, ask how. Get hate from everyone and probably the question will be closed. Or 2) Go to code golf, ask others how they'd do it. Get a handful of creative answers to select from, and the question is so popular it gets on the network-wide "hot" list. Mua ha ha ha ha. \$\endgroup\$
    – rumtscho
    Feb 22, 2014 at 15:31
  • 5
    \$\begingroup\$ @rumtscho You know, that's a good general strategy. Ok guys, for my next challenge, let's see who can write the smallest firmware for the prototype device sitting on my desk that meets all of the requirements in the linked document. To spice it up, this must be done by 8AM Monday morning. Go! \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 19:21

25 Answers 25

50
\$\begingroup\$

Bash script, 3 chars (Shortest, possibly the most elegant, though admittedly controversial)

$0&

Simply places a new instance of itself in the background (new process), then quits. The new instance likely will remain in the scheduler run-queue until the previous instance is done.

Warning - this is hard to kill, as the PID is continually changing. Temporarily renaming the script file is probably the simplest way to break the cycle.

A single-core system is assumed. Of course this is not realistic with Linux on modern bare-metal hardware, but it is easily configurable when running in a VM. We could probably achieve a similar trick using taskset, but that would reduce the impact of the 3-char solution.

This answer bends the rules a little bit in that it applies a specific meaning of "running". There will be moments when the new process has been fork()ed and the old process is still alive - i.e. it may be possible to observe more than one PID. However the new process will be placed on the Linux scheduler run-queue to wait for CPU cycles, while the existing process will continue to execute. At this point all that needs to be done by the existing process is for bash itself to exit(). This does take a finite amount of time, though I'm fairly confident that it will be done way before the current timeslice/scheduler quantum is done. Supporting evidence is the fact that bash starts up and shuts down in 2ms on my VM:

$ time bash -c :

real    0m0.002s
user    0m0.000s
sys 0m0.000s
$ 

Further supporting evidence that the new process does not actually run until the previous process is done can be seen in strace output:

strace -f -tt -o forever.strace bash -c ./forever.sh 

In the output, we see the original process has PID 6929. We can see the fork() call (actually clone()), which returns a new PID of 6930. At this point there are 2 PIDs, but only 6929 is currently running:

6929  12:11:01.031398 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f2f83ac49d0) = 6930
6929  12:11:01.031484 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
6929  12:11:01.031531 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
6929  12:11:01.031577 rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
6929  12:11:01.031608 rt_sigprocmask(SIG_SETMASK, [CHLD], NULL, 8) = 0
6929  12:11:01.031636 rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
6929  12:11:01.031665 rt_sigprocmask(SIG_SETMASK, [CHLD], NULL, 8) = 0
6929  12:11:01.031692 rt_sigprocmask(SIG_BLOCK, [CHLD], [CHLD], 8) = 0
6929  12:11:01.031726 rt_sigprocmask(SIG_SETMASK, [CHLD], NULL, 8) = 0
6929  12:11:01.031757 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
6929  12:11:01.031803 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
6929  12:11:01.031841 read(255, "", 4)  = 0
6929  12:11:01.031907 exit_group(0)     = ?
6930  12:11:01.032016 close(255)        = 0
6930  12:11:01.032052 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

Full strace output here.

We can see that 6930 does not issue any system calls until 6929 is completely done. It is reasonable to assume that this means 6930 does not run at all until 6929 is done. The perf utility would be the ultimate way to prove this.

\$\endgroup\$
11
  • 22
    \$\begingroup\$ "restarts ..., then quits", so more than one instances are running at the same time? \$\endgroup\$
    – microbian
    Feb 21, 2014 at 16:14
  • 4
    \$\begingroup\$ "...on single core" - yes, I would guess so too. On a many-core, you may probable be able to see many. \$\endgroup\$
    – blabla999
    Feb 21, 2014 at 16:31
  • 3
    \$\begingroup\$ If this was tagged code-golf, then this will definitely win! +1 \$\endgroup\$
    – John Odom
    Feb 21, 2014 at 21:43
  • 3
    \$\begingroup\$ @DigitalTrauma You're making huge assumptions about how long it takes bash to shut itself down. top tells you nothing -- it only updates once every few (tens of) seconds but you're spawning many processes per second. \$\endgroup\$ Feb 22, 2014 at 10:16
  • 2
    \$\begingroup\$ @DavidRicherby - you're absolutely right - top is not the right tool to use here. However I see that time bash -c : takes only 2ms on my Ubuntu VM, so I don't think its unreasonable to expect bash to complete its shutdown before its scheduling quantum is done. \$\endgroup\$ Feb 22, 2014 at 18:47
26
\$\begingroup\$

Solution 1

PHP, 32 chars

It sends the header and then it stops. After 3 seconds, the page gets reloaded.

file a.php

header("Refresh: 3; url=a.php");

This can be stopped by terminating the execution of the page before the headers are sent, or simply by killing the browser.


Solution 2

PHP, 2 pages

Let's consider the two files two different programs. The two files are in the same folder.

file a.php

header("Location:b.php");

file b.php

header("Location:a.php");

Terminating one of the pages before the headers are sent terminates the program (killing the browser works, too).

Here's the same program in

ASP.NET

file a.aspx

Response.Redirect("b.aspx")

file b.aspx

Response.Redirect("a.aspx")
\$\endgroup\$
7
  • 1
    \$\begingroup\$ That's a nice solution. I hope others come with answers different than this. That's why I kept it as a popularity contest. \$\endgroup\$
    – microbian
    Feb 21, 2014 at 16:10
  • \$\begingroup\$ Whether your 3 second reload answer is valid or not, I leave it to the php experts. I think it might be valid, because it is the browser who is waiting not your php (I am no expert). \$\endgroup\$
    – microbian
    Feb 21, 2014 at 16:29
  • 1
    \$\begingroup\$ While technically PHP is run as a module of a web server and your web server didn't restart, I think it is valid if you consider a .php file as a script and the script is run multiple times. \$\endgroup\$
    – TwiNight
    Feb 21, 2014 at 16:43
  • \$\begingroup\$ @TwiNight Thanks for the feedback, I appreciate it :) \$\endgroup\$
    – Vereos
    Feb 21, 2014 at 16:49
  • 3
    \$\begingroup\$ For your second solution, wouldn't the browser detect a redirect loop and stop on its own? thedan1984.com/wp-content/uploads/2012/02/… \$\endgroup\$
    – Ajedi32
    Feb 21, 2014 at 19:29
19
\$\begingroup\$

sh

echo $PWD/$0 | at tomorrow

This will work on any Posix-compliant system.

To kill it, delete the file or use atrm.

\$\endgroup\$
18
\$\begingroup\$

bash

exec "$0"

exec replaces the shell without creating a new process. This makes sure that there cannot be a second instance.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Better put it in ~/.bash_profile! \$\endgroup\$
    – yegle
    Feb 22, 2014 at 7:01
  • \$\begingroup\$ @yegle: $0 is -bash when .bash_profile is sourced, so that would just result in a syntax error. \$\endgroup\$
    – Dennis
    Feb 23, 2014 at 21:12
  • \$\begingroup\$ Oops, you are right. \$\endgroup\$
    – yegle
    Feb 24, 2014 at 3:59
  • \$\begingroup\$ exec ${0##-} in ~/.bash_profile works :-) \$\endgroup\$
    – yegle
    Mar 31, 2014 at 16:57
15
\$\begingroup\$

Windows Task Scheduler (Native)

C++. A nightmare of COM programming. Meets all challenge requirements.

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <taskschd.h>
#include <comutil.h>

#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsuppw.lib")    

static void timeplus (int seconds, char timestr[30]);


int main () {

    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    CoInitializeSecurity(NULL, -1, NULL, NULL,
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
        RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);

    const char *name = "Restarter";

    char path[MAX_PATH + 1];
    GetModuleFileNameA(NULL, path, sizeof(path));
    path[sizeof(path) - 1] = 0; // workaround for xp

    ITaskService *taskman;
    CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER,
        IID_ITaskService, (void **)&taskman);

    taskman->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());

    ITaskFolder *root;
    taskman->GetFolder(_bstr_t("\\"), &root);

    // Delete the task.
    root->DeleteTask(_bstr_t(name), 0);

    // pause for 5 seconds to give user a chance to kill the cycle
    fprintf(stderr, "If you want to kill the program, close this window now.\n");
    Sleep(5000);
    fprintf(stderr, "Sorry, time's up, maybe next time.\n");

    // Create the task for 5 seconds from now.
    ITaskDefinition *task;
    taskman->NewTask(0, &task);

    IPrincipal *principal;
    task->get_Principal(&principal);
    principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);

    ITaskSettings *settings;
    task->get_Settings(&settings);
    settings->put_StartWhenAvailable(VARIANT_TRUE);
    settings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
    settings->put_StopIfGoingOnBatteries(VARIANT_FALSE);

    ITriggerCollection *triggers;
    task->get_Triggers(&triggers);

    ITrigger *trigger;
    triggers->Create(TASK_TRIGGER_TIME, &trigger);

    char when[30];
    ITimeTrigger *trigger_time;
    trigger->QueryInterface(IID_ITimeTrigger, (void **)&trigger_time);
    trigger_time->put_Id(_bstr_t("TimeTrigger"));
    timeplus(10, when);
    trigger_time->put_StartBoundary(_bstr_t(when));
    timeplus(300, when);
    trigger_time->put_EndBoundary(_bstr_t(when));

    IActionCollection *actions;
    task->get_Actions(&actions);

    IAction *action;
    actions->Create(TASK_ACTION_EXEC, &action);

    IExecAction *action_exec;
    action->QueryInterface(IID_IExecAction, (void **)&action_exec);
    action_exec->put_Path(_bstr_t(path));

    IRegisteredTask *regtask;
    root->RegisterTaskDefinition(_bstr_t(name), task,
        TASK_CREATE_OR_UPDATE, _variant_t(), _variant_t(),
        TASK_LOGON_INTERACTIVE_TOKEN, _variant_t(""),
        &regtask);

    regtask->Release();
    action_exec->Release();
    actions->Release();
    trigger_time->Release();
    trigger->Release();
    triggers->Release();
    settings->Release();
    principal->Release();
    task->Release();
    root->Release();
    taskman->Release();
    CoUninitialize();

}


// outputs current utc time + given number of seconds as 
// a string of the form YYYY-MM-DDTHH:MM:SSZ
static void timeplus (int seconds, char timestr[30]) {

    SYSTEMTIME when;
    FILETIME whenf;
    LARGE_INTEGER tempval;

    GetSystemTimeAsFileTime(&whenf);
    tempval.HighPart = whenf.dwHighDateTime;
    tempval.LowPart = whenf.dwLowDateTime;
    tempval.QuadPart += seconds * 10000000LL; // 100 nanosecond units
    whenf.dwHighDateTime = tempval.HighPart;
    whenf.dwLowDateTime = tempval.LowPart;
    FileTimeToSystemTime(&whenf, &when);

    sprintf(timestr, "%04hu-%02hu-%02huT%02hu:%02hu:%02huZ",
        when.wYear, when.wMonth, when.wDay,
        when.wHour, when.wMinute, when.wSecond);

}

Compile with MSVC (or MinGW GCC if you have all dependencies).

Program will start and register a one-time task with the Windows task scheduler to start itself 5 seconds later (Control Panel -> Administrative Tools -> Task Scheduler to view, task is named "Restarter"). Program will pause for 5 seconds to give you a chance to kill it before it creates the task.

Challenge Requirements:

  • Starts itself again when finishes. Yes. Task is scheduled just prior to program exit.

  • No more than one instance of the program running at same time. Yes. Program exits fully and does not run for 5 seconds. It is started by the scheduler.

  • You can ignore any instance that is manually started by user during your cycle. Yes, as a side-effect of using a constant task name.

  • As long as it is guaranteed that it starts again. Yes, provided that Task Scheduler is running (it is in a standard Windows configuration).

  • The only way to stop the cycle is to kill the process. Yes, the process can be killed during the 5 second window while it is running. The program deletes the task prior to the 5 second delay, killing it at this time will not leave a stray task in the scheduler.

  • Your solution should not involve restarting of the environment Yes.

By the way, if anybody ever wondered why Windows applications used to be so unstable (before the advent of .NET and C#), this is one reason why. The amount of error handling required (had I included it), resource management, and verbosity sets up very error-prone situations if a programmer is even the slightest bit lazy (the above code is extremely lazy).

A much easier and shorter alternative is to invoke schtasks.exe. I have submitted a version with that in a .BAT script as well.

\$\endgroup\$
0
13
\$\begingroup\$

BBC BASIC - a tribute to Snow Patrol

Emulator at bbcbasic.co.uk

This one's a little different. It prints a verse of the song "Run" and plays an arpeggio of the chords so you can sing along. It was inspired by the fact that the command to execute (and therefore the last line of the program) is of course RUN.

All variables are cleared at the start of the program, so it takes the screen colour left behind by the previous iteration to decide what verse to print next.

    5 C=POINT(0,0) MOD 4
   10 COLOUR 129+C
   15 CLS
   20 RESTORE 110+C
   25 READ A$
   30 PRINT A$
   35 FORK = 1 TO 4
   40   RESTORE K+100
   45   READ P
   50   FORM= 1 TO 8
   55     SOUND 1,-15,P,7
   60     SOUND 1,-15,P-20,7
   65   NEXT
   70 NEXT
  101 DATA 100
  102 DATA 128
  103 DATA 136
  104 DATA 120
  110 DATA Light up light up - As if you have a choice - Even if you can not hear my voice - I'll be right beside you dear.
  111 DATA Louder louder - And we'll run for our lives - I can hardly speak - I understand - Why you can't raise your voice to say.
  112 DATA Slower Slower - We dont have time for that - All I want is to find an easier way - To get out of our little heads.
  113 DATA Have heart my dear - We're bound to be afraid - Even if its just for a few days - Makin' up for all of this mess.
  120 RUN

OUTPUT (montage of 4 different screen shots)

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ +1 for the color solution as "shared memory" alternative. \$\endgroup\$ Feb 21, 2014 at 22:03
11
\$\begingroup\$

HTML/JavaScript:

<form /><script>document.forms[0].submit()</script>

The code triggers the destruction of the page it is running on, then the re-creation of another instance of itself when the browser loads the page anew.

AFAIK, the only way out is to kill the tab the page is running in.

EDIT: as per popular request, a valid HTML5 code:

<!doctype html><meta charset=utf-8><title> </title><form></form>
<script>document.forms[0].submit()</script>
\$\endgroup\$
1
  • \$\begingroup\$ @JasonC I disagree. I think that reasonable pages should comply with the specs, but popularity-contests are quite supposed to be reasonable, are they? :D so +1, I really like this one. \$\endgroup\$
    – yo'
    Feb 22, 2014 at 12:41
10
\$\begingroup\$

C

This program acts like a lot of malware. Just before it closes, it creates a shell script in the /tmp directory. It forks to start the shell script, which lets the original program close and cancel the original PID. After a brief period of time (2 seconds) the shell script starts a new process with the program. For brevity, the program location is hard-wired as '/tmp/neverend/'.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

void rebirth(){
    char t[] = "/tmp/pawnXXXXXX";
    char* pawnfile = mktemp(t);
    if(pawnfile){
        int fd = open(pawnfile, O_RDWR|O_CREAT);
        const char msg[]="sleep 2\n/tmp/neverend\n";
        if(fd>0){
            int n = write(fd, msg, sizeof(msg));
            close(fd);
            pid_t pid = fork();
            if(pid==0){
                char* args[3] = {"bash", pawnfile, NULL};
                execvp(args[0], args);
            }
        }
    }
}

int main(int argc, char* argv[]){
    printf("Starting %s\n", argv[0]);
    atexit(rebirth);
    printf("Exiting %s\n", argv[0]);
}

There is only ever one 'neverend' process running at a time. Each new process gets a new PID. The easiest way to kill this is to delete the executable. If you wanted to make it more malignant, you could copy both the executable and the script to make sure there are multiple copies on the program on disk at any time.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ I am expecting to see more innovative answers. See comments for question about 'supplement programs'. To me, a supplement program is just a part of your program that hangs around. \$\endgroup\$
    – microbian
    Feb 21, 2014 at 17:35
  • 4
    \$\begingroup\$ Forking means you'll have two instances of the process running at the same time, even if they're doing different things. \$\endgroup\$ Feb 21, 2014 at 20:39
  • \$\begingroup\$ @BarryFruitman easy to avoid, though, by really using two different executables. It's valid then, but way less elegant. \$\endgroup\$ Feb 21, 2014 at 22:00
  • \$\begingroup\$ I suppose you could use system() if the rules don't count a fork+exec to /bin/sh as a supplementary program. \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 6:07
10
\$\begingroup\$

Perl

`perl -e"kill 9,$$"|perl $0`

The script issues a system command to kill itself, and pipe the result into another instance of itself. The Perl interpreter is used to do the killing, for cross platform reasons.

Stop the madness by deleting the script.

\$\endgroup\$
7
\$\begingroup\$

Atari 8-bit Basic

1L.:R.

Tokenizes to:

1 LIST : RUN

Internally it is clearing the internal structures, essentially wiping out the program, before running it again from the listing.

This is fundamentally different from:

1L.:G.1

Which tokenizes to:

1 LIST : GOTO 1

This is a basic infinite loop. When you run them, you see the difference in speed (first is slower).

\$\endgroup\$
5
  • \$\begingroup\$ I'm not quite clear why "list" during program execution would clear out any interenal structures. I think the Atari has a keyboard buffer, so one could list the program, stuff the keystrokes to run it, and do a "new" with the cursor positioned to "retype" it. \$\endgroup\$
    – supercat
    Feb 22, 2014 at 18:43
  • \$\begingroup\$ @supercat - LIST doesn't, RUN does. \$\endgroup\$
    – user15259
    Feb 22, 2014 at 23:09
  • \$\begingroup\$ By that logic, one could omit the "LIST". On the other hand, if the program stuffed the keyboard buffer, with a few carriage returns, put "NEW" followed by the program and "RUN" at the right spots on screen, homed the cursor, and exited, it would genuinely erase itself and retype itself automatically. \$\endgroup\$
    – supercat
    Feb 23, 2014 at 16:03
  • \$\begingroup\$ @supercat - without the LIST, you wouldn't see it running. I chose LIST because it has the shortest input L.. I like the idea of putting that into a keyboard buffer, it's certainly short enough! \$\endgroup\$
    – user15259
    Feb 24, 2014 at 15:03
  • \$\begingroup\$ Am I remembering correctly that the Atari, like the Commodore machines, reads text off the screen when you push Return? How big is the keyboard buffer? On the VIC-20 and C64, it's ten bytes. A program which does enough pokes to load the keyboard buffer probably wouldn't fit in the keyboard buffer, but I've written programs which would modify themselves by printing changes to the screen followed by RUN, and stuff a few Return keystrokes. Such things were especially useful on the 64 since it didn't have the [IIRC] IN command the Atari has for merging lines into a program. \$\endgroup\$
    – supercat
    Feb 24, 2014 at 16:09
5
\$\begingroup\$

On an IBM Mainframe running z/OS, you run a utility which copies a dataset (file) to another dataset (file). The input is the source of the JCL (Job Control Language) that you have submitted to cause it to run. The output is the Internal Reader (INTRDR). You will also need to ensure that your system does not allow the running of multiple identical jobnames. Good to use a job-class which only has one initiator (place where a JOB can run in batch).

There are no PIDs involved (in z/OS), so fails the challenge set.

You halt the process by draining and/or flushing. If something has gone wrong, by draining and/or flushing, swearing, kicking, attempting a warm-start and finally by a cold-start or hitting the Big Red Button (and shooting the programmer).

I may have exaggerated along the way, but don't try this at work...

Example using SORT. Details on the JOB card are very site-dependant. Site policy may either forbid or prevent the use of INTRDR. A specific class may be required to use the INTRDR. If your site policy forbids its use do not use it unless you want to take your belongings for a walk in a cardboard box.

Although there are good uses for the INTRDR, do not use it for this purpose. You won't even have a chance to get your box.

//jobname JOB rest is to your site standards
//* 
//STEP0100 EXEC PGM=SORT 
//SYSOUT   DD SYSOUT=* 
//SORTOUT  DD SYSOUT=(,INTRDR) minimum required, site may require more 
//SYSIN    DD * 
  OPTION COPY 
//SORTIN   DD DISP=SHR,DSN=YOUR.LIBRARY.WITHJOB(JOBMEMBR) 

Other utilities are available. A quick program would be easy to do as well, just read a file, write a file.

If you want an example of this going wrong, try: http://ibmmainframes.com/viewtopic.php?p=282414#282414

The traditional way to copy a dataset is to use the IBM utility IEBGENER, as ugoren alludes in their comment.

However, these days, many sites will have IEBGENER "aliased" to ICEGENER. ICEGENER will, if it can, use IBM's DFSORT (or its rival SyncSort) to do a copy, because the SORT products are much more hihgly optimised for IO than IEBGENER is.

I'm just cutting out the middle-man by using SORT.

If you work at an IBM Mainframe site, you know the format of the JOB card that you should use. The minimal JOB card is as I have shown, without the comment. The comment will be important, because you may be supposed to be supplying accounting information, for instance. The jobname will likely have a site-specific format.

Some sites ban, or prevent, the use of the INTRDR. Be aware.

Some sites allow multiple jobs with the same name to run at the same time. Be aware.

Although unless you are a System's Programmer you can't set up such a class, you should look for a class which allows only one initiator. With that, the process is fairly safe - but be absolutely sure about that the class is working as described. Test. Not with this job.

If you are a System's Programmer, you know not to do anything outside of your remit. 'nuff said.

With one job with the same name allowed at the same time and a single initiator, this will be a constant stream of job start/finish next job start/finish - until you fill the spool (another bad thing to do) with the output from thousands of jobs (or run out of job numbers). Watch a JES Console for warning messages.

Basically, don't do this. If you do do it, don't do it on a Production machine.

With a little brushing up, I'll consider another Answer for how to do it on another IBM Mainframe operating system, z/VSE... z/VSE uses JCL. z/OS uses JCL. They are different :-)

\$\endgroup\$
3
  • \$\begingroup\$ The idea looks good, but it isn't an answer. Show us the JCL - JOB, EXEC and DD - then it will be an answer. \$\endgroup\$
    – ugoren
    Feb 21, 2014 at 20:49
  • \$\begingroup\$ Haven't submitted a job for an awful long, so I'm not sure what to make of it. If the missing parts are just local customization, then OK. But if you hide stuff to prevent an abuse, then make up your mind - post the real thing, or post nothing. P.S. We used IEBGENER back then to simply copy. \$\endgroup\$
    – ugoren
    Feb 21, 2014 at 22:15
  • \$\begingroup\$ @ugoren Further update, including explanation of why IEBGENER was not selected for the task. Removing the comment text on the JOB statement gives the necessary JCL for it to run, but it being sufficient JCL depends on local site standards, either for the job to work or for the programmer to avoid being sacked. \$\endgroup\$ Feb 21, 2014 at 23:21
5
\$\begingroup\$

Windows Task Scheduler (.BAT)

Windows batch script. Meets all challenge requirements.

As far as I can see this is the only Windows solution so far that meets all requirements and has no nonstandard dependencies (my other solution is similar but requires compilation).

@ECHO OFF
SETLOCAL

schtasks /Delete /TN RestarterCL /F

ECHO Close this window now to stop.
TIMEOUT /T 5

FOR /f "tokens=1-2 delims=: " %%a IN ("%TIME%") DO SET /A now=%%a*60+%%b
SET /A start=%now%+1
SET /A starth=100+(%start%/60)%%24
SET /A startm=100+%start%%%60
SET /A end=%now%+3
SET /A endh=100+(%end%/60)%%24
SET /A endm=100+%end%%%60

schtasks /Create /SC ONCE /TN RestarterCL /RI 1 /ST %starth:~1,2%:%startm:~1,2% /ET %endh:~1,2%:%endm:~1,2% /IT /Z /F /TR "%~dpnx0"

ENDLOCAL

Program behaves similarly to my C++/COM answer.

Program will start and register a one-time task with the Windows task scheduler to start itself up to 60 seconds later (Control Panel -> Administrative Tools -> Task Scheduler to view, task is named "Restarter"). Program will pause for 5 seconds to give you a chance to kill it before it creates the task.

Makes use of command line Task Scheduler interface schtasks.exe. Arithmetic in script is to compute time offsets while keeping the time valid and in HH:MM format.

Challenge Requirements:

  • Starts itself again when finishes. Yes. Task is scheduled just prior to program exit.

  • No more than one instance of the program running at same time. Yes. Program exits fully and does not run for ~60 seconds. It is started by the scheduler.

  • You can ignore any instance that is manually started by user during your cycle. Yes, as a side-effect of using a constant task name.

  • As long as it is guaranteed that it starts again. Yes, provided that Task Scheduler is running and schtasks.exe is present (both true in default Windows configurations).

  • The only way to stop the cycle is to kill the process. Yes, the process can be killed during the 5 second window while it is running. The program deletes the task prior to the 5 second delay, killing it at this time will not leave a stray task in the scheduler.

  • Your solution should not involve restarting of the environment Yes.

Note: Due to limited command line interface, restart time must be specified in minutes and the task will not restart on laptops without the AC adapter plugged in (sorry).

\$\endgroup\$
4
\$\begingroup\$

Python (72 bytes)

import os
os.system('kill -9 %s && python %s' % (os.getpid(), __file__))

Could be make smaller I guess. First, by hardcoding the name of the file (instead of using __file__). But here, you can put this code in a file and run it, whatever its name is :)

\$\endgroup\$
4
  • \$\begingroup\$ You can probably change && to &. \$\endgroup\$
    – user10766
    Feb 21, 2014 at 23:52
  • 1
    \$\begingroup\$ Since when is that allowed, user2509848? \$\endgroup\$
    – Rhymoid
    Feb 22, 2014 at 1:02
  • \$\begingroup\$ Well, you could start by removing the whitespace… \$\endgroup\$
    – Ry-
    Feb 22, 2014 at 2:11
  • 6
    \$\begingroup\$ Since it's not tagged code-golf, I will keep the code like this :-) \$\endgroup\$ Feb 22, 2014 at 8:53
4
\$\begingroup\$

Unix shell

I haven't seen many solutions yet that rely on an unrelated program to restart it. But this is exactly what the at(1) utility was made for:

echo "/bin/sh $0"|at now + 1 minute

It's hard to actually catch the program running, since it only runs once per minute and exits so quickly. Fortunately the atq(1) utility will show you that it's still going:

$ atq
493     Fri Feb 21 18:08:00 2014 a breadbox
$ sleep 60
$ atq
494     Fri Feb 21 18:09:00 2014 a breadbox

And atrm(1) will allow you to break the cycle:

$ atq
495     Fri Feb 21 18:10:00 2014 a breadbox
$ atrm 495
$ atq

You can replace 1 minute with 1 hour, or 1 week. Or give it 1461 days to have a program that runs once every 4 years.

\$\endgroup\$
2
\$\begingroup\$

PowerShell

I am abusing (and possibly breaking) my own rule.

[System.Threading.Thread]::Sleep(-1)

It takes infinite amount of time to restart itself.
It can be killed by killing the host process.

Just wait and see ;)

\$\endgroup\$
5
  • 5
    \$\begingroup\$ +1 for creativity, but -1 for cheating. \$\endgroup\$ Feb 21, 2014 at 22:06
  • 2
    \$\begingroup\$ Ha, but is it "guaranteed that it starts again" if it never stops? \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 6:04
  • \$\begingroup\$ That's why I said I probably be breaking the rule. It's the philosophical beauty of infinity that you can assume that anything can happen after that. Turing machine works that way too. \$\endgroup\$
    – microbian
    Feb 22, 2014 at 6:50
  • 1
    \$\begingroup\$ -100 because I don't support you winning your own contest, especially on a technicality, but +101 because waiting for it to restart is the best procrastination excuse ever. \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 8:00
  • \$\begingroup\$ Well, you know, then while true; do sleep 1; done quilifies, doesn't it? \$\endgroup\$
    – yo'
    Feb 22, 2014 at 12:40
2
\$\begingroup\$

Bash

echo -e "$(crontab -l)\n$(($(date "+%M")+1)) $(date '+%H %e %m * /repeat.sh')" | crontab -

Save this as repeat.sh in the / directory and give it execute permission. It can be killed by deleting the file

This works by putting an entry in the crontab to run it 1 minute later.

\$\endgroup\$
2
\$\begingroup\$

Visual Base 6 :)

Sub Main:Shell "cmd ping 1.1.1.1 -n 1 -w 500>nul&&"""&App.Path &"\"&App.EXEName& """":End Sub

To run, create a new project, add a module with this code, set the start-up object to "Sub Main", compile, and then run the executable.


More readable version:

Sub Main()
    Call Shell("cmd ping 1.1.1.1 -n 1 -w 3000 > nul && """ & App.Path & "\" & App.EXEName & """")
End Sub
\$\endgroup\$
1
  • \$\begingroup\$ VB6 is a real man's VB. The last of its kind! \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 5:59
2
\$\begingroup\$

JavaScript

Without "going to the network" when not necessary :-) JavaScript's event loop scheduling allows us to write programs that fulfill the given requirements very easily:

(function program() {
    // do what needs to be done
    setTimeout(program, 100);
})();

This "restarts" the program function at a 10-times-per-second pace. It is guaranteed by JavaScript's nature that only a single task will be running at the same time, and it does not "restart the environment" as in "reload the page".

\$\endgroup\$
1
\$\begingroup\$

HTML / JAVASCRIPT

HTML FILE a.html

<script>window.location = "a.html"</script>
\$\endgroup\$
1
\$\begingroup\$

Bash

Longer than it has to be, but I'm tired, and don't care :)

while true; do sleep 1; done; bash $0;

You said that it has to restart itself when it finishes, you didn't specifically say that it had to do so repeatedly, or indefinitely. Also, you said that it should never have two instances running at once... it never will. ;)

There are any great number of ways to do this. My personal favorite, would be to do something like send a packet somewhere distant, and then (via any number of methods), have the response trigger the process.

\$\endgroup\$
3
  • \$\begingroup\$ Technically, the sleep process restarts when it finishes \$\endgroup\$
    – user12205
    Feb 22, 2014 at 9:07
  • \$\begingroup\$ If the program is a program that restarts itself, then it is implied that it has to do so indefinitely -- otherwise it is restarting something else that isn't itself. \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 20:54
  • \$\begingroup\$ @Jason C: Without getting too philosophical, to the extent that it possibly can, it does restart itself. We could debate how complex it has to be to truly restart itself, but I think that's well beyond what the author meant. Though, if you want it to really restart itself, then it would probably be something that uses goto, or JMP, or whatever construct your language may offer, to go back to the start, so it's "restarting" itself. Otherwise, it's just executing something that is distinctly like itself. But then someone will likely take issue that that's not truely restarting. So I digress. \$\endgroup\$ Feb 25, 2014 at 7:29
1
\$\begingroup\$

Android: An alarm will restart the Activity after 1 second

public class AutoRestart extends Activity
{

@Override
public void onCreate()
{
    finish();
}

@Override
public void onDestroy() {

    Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
    restartServiceIntent.setPackage(getPackageName());

    PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(
            AlarmManager.ELAPSED_REALTIME,
            SystemClock.elapsedRealtime() + 1000,
            restartServicePendingIntent);

    super.onDestroy();
}

}
\$\endgroup\$
1
\$\begingroup\$

C + MPI Environment

mpifork.c:

#include <stdio.h>

main(int argc, char * argv[])
{
    srand(time(NULL));
    int host = rand()%(argc-1)+1;
    FILE * logFile = fopen("mpifork.log", "a");
    if(logFile == NULL){
        fprintf(stderr, "Error: failed to open log file\n");
    } else {
        fprintf(logfile, "Jumping to %s\n", argv[host]);

        char * args[argc+5];
        args[0] = "mpirun";
        args[1] = "-H";
        args[2] = argv[host];
        args[3] = argv[0];
        for(host = 0; host < argc-1; host++) args[host+4] = argv[host+1];
        args[argc+3] = NULL;

        execvp("mpirun", args);
        fprintf(stderr, "exec died\n");
        perror("execvp");
    }
}

You must have OpenMPI or some other MPI implementation installed. Compile with

mpicc -o mpifork mpifork.c

Now that I think about it, there's no reason you have to use mpicc - gcc or whatever compiler will work. You just have to have mpirun.

gcc -o mpifork mpifork.c

To run it, you should probably include the full path name, and include a list of hosts. For example, I added some entries in /etc/hosts that all pointed to localhost, and ran it like this:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

The executable must be in the same directory on any machine that you want to run this on.


Essentially, this takes a list of hosts provided on the command line, selects one of the hosts, and launches the executable on the target host with the same arguments. If everything goes perfectly, mpirun will call itself over and over on different machines (or the same machine if you only provide 'localhost'. The executable itself (mpifork) does terminate - after calling execvp, it is no longer executing on the first machine.

If you wanted to be evil, you could instead make this launch on every machine, by including the full list of hosts that is provided on the command line in args. That would re-spawn a copy of itself on every machine, over and over - a cluster forkbomb.

However, in this form, I'm pretty sure this satisfies the rules.

\$\endgroup\$
0
\$\begingroup\$

x86 Assembly

Not entirely sure this fits your criteria as it doesn't spawn a new process, but here it is anyway.

The program will show a message box, allocate some memory, copy its own code section into the allocated memory, and then jump to that location starting the cycle over. It should run until malloc fails.

format PE GUI 4.0
entry a

include 'include/win32a.inc'

section '.text' code readable executable

    a:
        push    0
        push    _caption
        push    _message
        push    0
        call    [MessageBoxA]

        push    b-a
        call    [malloc]

        push    b-a
        push    a
        push    eax
        call    [memcpy]

        call    eax
    b:

section '.data' data readable writeable

    _caption db 'Code challenge',0
    _message db 'Hello World!',0

section '.idata' import data readable writeable

    library user,'USER32.DLL',\
        msvcrt,'msvcrt.dll'

    import user,\
        MessageBoxA,'MessageBoxA'

    import msvcrt,\
        malloc,'malloc',\
        memcpy,'memcpy'

Compiled with fasm.

\$\endgroup\$
5
  • 5
    \$\begingroup\$ Since it is part of your program to call the newly copied code, so technically your program never finished at all. \$\endgroup\$
    – microbian
    Feb 21, 2014 at 17:53
  • 6
    \$\begingroup\$ From a low level viewpoint, the same could be said of all the programs here. :-) \$\endgroup\$ Feb 21, 2014 at 21:25
  • \$\begingroup\$ @BrianKnoblauch I disagree. The most interesting answers here seem to modify the system environment so that a new copy of the process is started some time after the first one is killed. For example, I would think that creating a chron job to run the process in the future would be a good way of letting the process completely die, then be restarted. \$\endgroup\$
    – Kevin
    Feb 22, 2014 at 0:26
  • 3
    \$\begingroup\$ @BrianKnoblauch Not really. A process is an operating system construct (which these days - as in since the advent of protected mode in the 286 in 1982 - is also backed by hardware via virtual address spaces and protected memory). When it ends, all that info goes away. While it wasn't stated explicitly in the challenge, I take the spirit of the challenge to mean that "restart" implies that a new process ID is assigned. \$\endgroup\$
    – Jason C
    Feb 22, 2014 at 5:54
  • \$\begingroup\$ Well, I would give +1 if you managed to free the memory on the way (please ping me by @ once you manage, since I likely won't keep my eye on it). \$\endgroup\$
    – yo'
    Feb 22, 2014 at 12:44
0
\$\begingroup\$

Linux upstart init

Given the strictest reading of the question, I think this is impossible. In essence it is asking for a program to spontaneously start with the help of no other running programs.

There are some at and chron-based answers, but with the strictest reading, atd and anacron are supplementary programs which are running all the time, so they may be disqualified.

A related approach, but a little lower level is to use Linux's init. As root, add this .conf file to /etc/init/:

description "forever"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

exec sleep 10

Then have init re-read its .conf files:

sudo telinit 5

This will start a sleep process which will live for 10 seconds, then exit. init will then respawn the sleep once it detects the previous one has gone away.

Of course this is still using init as a supplementary program. You could argue that init is a logical extension of the kernel and will always be available in any Linux.

If this is not acceptable, then I guess the next lower-level thing to do would be to create a kernel module which respawns a userspace process (not sure how easy that is). Here it can be argued that the kernel is not a process, and therefore not a program (supplementary). On the other hand, the kernel is a program in its own right, from the point of the CPU.

\$\endgroup\$
-1
\$\begingroup\$

TI-BASIC: 5 characters

call it prgmA

:prgmA
\$\endgroup\$
4
  • \$\begingroup\$ I can count 6 chars. Is there anything special about counting TI-BASIC program size? \$\endgroup\$
    – user12205
    Feb 22, 2014 at 15:37
  • \$\begingroup\$ The : is just the start of line symbol whenever you're programming in TI-basic. It's not something you type in, it's just there in the editor. \$\endgroup\$
    – scrblnrd3
    Feb 22, 2014 at 16:27
  • \$\begingroup\$ Isn't that recursive invocation? Try incrementing A and using a value of it as a base case, you'll see it stepping out eventually. \$\endgroup\$
    – nanofarad
    Feb 23, 2014 at 1:24
  • \$\begingroup\$ Well all variables are globals in ti-basic, so I'm not sure. It might be \$\endgroup\$
    – scrblnrd3
    Feb 23, 2014 at 2:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.