Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #400064 > unrolled thread
| Started by | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| First post | 2026-06-15 11:10 +0200 |
| Last post | 2026-06-27 22:02 -0700 |
| Articles | 8 — 5 participants |
Back to article view | Back to comp.lang.c
Great code Bonita Montero <Bonita.Montero@gmail.com> - 2026-06-15 11:10 +0200
Re: Great code Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-16 07:39 +0000
Re: Great code Bonita Montero <Bonita.Montero@gmail.com> - 2026-06-16 09:57 +0200
Re: Great code Paul <nospam@needed.invalid> - 2026-06-27 07:20 -0400
Re: Great code Michael S <already5chosen@yahoo.com> - 2026-06-27 21:28 +0300
Re: Great code Paul <nospam@needed.invalid> - 2026-06-27 16:53 -0400
Re: Great code Michael S <already5chosen@yahoo.com> - 2026-06-28 02:07 +0300
Re: Great code "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-06-27 22:02 -0700
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2026-06-15 11:10 +0200 |
| Subject | Great code |
| Message-ID | <110ofim$820a$1@raubtier-asyl.eternal-september.org> |
I've written a tool called "bg" to combine Windows' runas with start.
One parameter is the affinity-mask for the processors which the star-
ted program is attached to. The below code is the parsing function.
The code wouldn't apply if this function has to be performance since
I work with regexes. But having this this way makes the code rather
short for what is required - imagine you'd have to do that in C.
bool params::state::checkAffinity( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--affinity" ) != 0 )
return false;
if( m_todo.size() < 2 )
{
m_todo = {};
m_errs.emplace_back( L"please specify affinity" );
cerr << "" << endl;
return false;
};
DWORD_PTR dwpAff = 0;
match_results<wstring_view::iterator> match;
defer chop2( [&] { m_todo = m_todo.subspan( 2 ); } );
wstring_view svPattern( m_todo[1] );
constexpr const wchar_t
*RxHex = L"^0x([0-9a-f]+)$",
*RxBin = sizeof( DWORD_PTR ) == 8 ? L"^b((?:[01]+){1,64})$" :
L"^b((?:[01]+){1,32})$",
*RxRange = L"^([0-9]+)(?:-([0-9]+))?(,)?";
if( wregex rxHex( RxHex, regex_constants::icase ); regex_match(
svPattern.begin(), svPattern.end(), match, rxHex ) )
wistringstream( wstring( svPattern ) ) >> hex >> dwpAff;
else if( wregex rxBinary( RxBin, regex_constants::icase );
regex_match( svPattern.begin(), svPattern.end(), match, rxBinary ) )
for( wchar_t c : wstring_view( match[1].first, match[1].second ) )
dwpAff = dwpAff << 1 | (c - '0');
else
{
defer affZero( [&] { dwpAff = 0; } );
auto it = svPattern.begin();
wregex rx( RxRange );
match_results<wstring_view::iterator> match;
for( ; regex_search( it, svPattern.end(), match, rx ); it =
match[0].second )
{
if( match[3].matched && match[3].second == svPattern.end() )
break;
unsigned from, to;
wistringstream( wstring( match[1].first, match[1].second )
) >> from;
if( match[2].matched )
{
wistringstream( wstring( match[2].first,
match[2].second ) ) >> to;
++to;
}
else
to = from + 1;
constexpr unsigned BITS = sizeof(ULONG_PTR) * 8;
if( from >= to || from >= BITS || to > BITS )
break;
constexpr DWORD_PTR ALL = -1;
DWORD_PTR dwpBits = ALL << from;
if( to < BITS )
dwpBits &= ~(ALL << to);
dwpAff |= dwpBits;
}
if( it == svPattern.end() )
affZero.disable();
}
if( !dwpAff )
{
wostringstream woss;
woss << "invalid affinity pattern: " << svPattern;
m_errs.emplace_back( woss.str() );
return true;
}
DWORD_PTR dwpProc, dwpSys;
GetProcessAffinityMask( GetCurrentProcess(), &dwpProc, &dwpSys );
if( (dwpAff &= dwpProc) )
pms.dwpAffinity = dwpAff;
return true;
}
[toc] | [next] | [standalone]
| From | Lawrence D’Oliveiro <ldo@nz.invalid> |
|---|---|
| Date | 2026-06-16 07:39 +0000 |
| Message-ID | <110qukc$uotb$1@dont-email.me> |
| In reply to | #400064 |
On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote: > I've written a tool called "bg" to combine Windows' runas with > start. Sort of a Windows answer to systemd? Somebody is already working on that <https://github.com/Jamesits/SvcGuest>. > One parameter is the affinity-mask for the processors which the > started program is attached to. They haven’t yet added that capability (which systemd has). Perhaps you could contribute code ...
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2026-06-16 09:57 +0200 |
| Message-ID | <110qvkh$v3nt$1@raubtier-asyl.eternal-september.org> |
| In reply to | #400078 |
Am 16.06.2026 um 09:39 schrieb Lawrence D’Oliveiro:
> On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote:
>> I've written a tool called "bg" to combine Windows' runas with
>> start.
> Sort of a Windows answer to systemd? Somebody is already working on that
> <https://github.com/Jamesits/SvcGuest>.
No, my tool has nothing to do with making arbitrary executables
runnable as services. It's a combination of Windows' runas, start
and Unix' time.
Here are the commandline options of my tool:
static const char usage[] =
"--console create new console\n"
"--detach start detached / hidden\n"
"--idle idle priority\n"
"--below below normal priority\n"
"--above above normal priority\n"
"--high high priority\n"
"--realtime realtime priority\n"
"--affintiy f CPU-affinity as hex (0x*), binary (b*) or list (e.g.
1,5-9)\n"
"--group g primary processor group\n"
"--wait wait for program to terminate\n"
"--logon u d p create process under 1. username, 2. domain and 3.
password\n"
"--no-profile don't load registry for --logon, just network-credentials\n"
"--dir d set startup directory\n"
"--times show process times (includes --wait)";
Here's the main source:
#include <Windows.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <cwchar>
#include <cstddef>
#include <system_error>
#include <cassert>
#include <sstream>
#include <functional>
#include <array>
#include <type_traits>
#include <cstdio>
#include <bit>
#include <span>
#include <regex>
#include <expected>
#include "defer.hpp"
#pragma warning(disable: 4554) // operator prececence
#pragma warning(disable: 26812) // prefer scoped enums
using namespace std;
struct params
{
wstring userName, domain, password;
bool noProfile = false;
wstring startupDir;
DWORD
dwPrioFlag = NORMAL_PRIORITY_CLASS,
dwConsoleFlag = 0;
DWORD_PTR dwpAffinity = -1;
WORD wGroup = -1;
bool wait = false;
wstring cmdLine;
bool times = false;
bool parse( int argc, const wchar_t *const *argv );
private:
struct state
{
using check_fn = bool (state::*)( params & );
static const check_fn g_checkFns[9];
span<const wchar_t *const> m_todo;
vector<wstring> m_errs;
bool checkNoProfile( params &pms );
bool checkLogon( params &pms );
bool checkDir( params &pms );
bool checkConsole( params &pms );
bool checkPriority( params &pms );
bool checkAffinity( params &pms );
bool checkGroup( params &pms );
bool checkWait( params &pms );
bool checkTimes( params &pms );
bool parse( params &pms, int argc, const wchar_t *const *argv );
};
};
static expected<wstring, DWORD> inputPassword();
static string formatTime( uint64_t t );
static string formatDotted( uintmax_t value );
int wmain( int argc, const wchar_t *const *argv )
{
try
{
params pms;
if( !pms.parse( argc, argv ) )
return EXIT_FAILURE;
const wchar_t *curDir = pms.startupDir.length() ?
pms.startupDir.c_str() : nullptr;
if( pms.userName.length() && !pms.password.length() )
{
cout << "password: ";
expected<wstring, DWORD> xptPass = inputPassword();
if( !xptPass )
throw exception( "error while password input" );
pms.password = *xptPass;
cout << endl;
}
BOOL cpRet;
bool suspended = pms.dwpAffinity != -1 || pms.wGroup != (WORD)-1;
DWORD dwCreationFlags = pms.dwPrioFlag | pms.dwConsoleFlag |
(!suspended ? 0 : CREATE_SUSPENDED);
STARTUPINFOW si { sizeof si };
PROCESS_INFORMATION pi;
if( !pms.userName.length() )
cpRet = CreateProcessW(
nullptr, (LPWSTR)pms.cmdLine.c_str(), nullptr, nullptr,
FALSE, dwCreationFlags, nullptr, curDir, &si, &pi );
else
cpRet = CreateProcessWithLogonW(
pms.userName.c_str(),
pms.domain.c_str(),
pms.password.c_str(),
pms.noProfile ? LOGON_NETCREDENTIALS_ONLY : LOGON_WITH_PROFILE,
nullptr, (LPWSTR)pms.cmdLine.c_str(),
dwCreationFlags, nullptr, curDir, &si, &pi );
if( !cpRet )
throw exception( "creating process failed" );
defer closeHandles( [&] { CloseHandle( pi.hProcess ); CloseHandle(
pi.hThread ); } );
defer terminate( [&] { TerminateProcess( pi.hProcess, EXIT_FAILURE ); } );
if( suspended )
{
bool threadAssigned = false;
if( pms.wGroup != (WORD)-1 )
{
GROUP_AFFINITY aff {};
DWORD dwNCPUs = GetActiveProcessorCount( pms.wGroup );
if( !dwNCPUs )
throw exception( "can't determine the number of processors in the
destination group" );
if( dwNCPUs < sizeof(KAFFINITY) * 8 )
aff.Mask = ((KAFFINITY)1 << dwNCPUs) - 1;
else
aff.Mask = -1;
aff.Group = pms.wGroup;
if( !SetThreadGroupAffinity( GetCurrentThread(), &aff, nullptr ) )
throw exception( "can't set primary thread's group affinity" );
threadAssigned = true;
}
if( pms.dwpAffinity != -1 )
if( !SetProcessAffinityMask( pi.hProcess, pms.dwpAffinity ) )
throw exception( "can't set process affinity mask" );
else if( !threadAssigned && !SetThreadAffinityMask( pi.hThread,
pms.dwpAffinity ) )
throw exception( "can't set primary thread's affinity mask" );
if( ResumeThread( pi.hThread ) == -1 )
throw exception( "can't resume main thread of process" );
}
terminate.disable();
if( !pms.wait )
return EXIT_SUCCESS;
if( WaitForSingleObject( pi.hProcess, INFINITE ) != WAIT_OBJECT_0 )
throw exception( "can't wait for end of program" );
DWORD dwExitCode;
if( !GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
throw exception( "can't get process exit code" );
if( !pms.times )
return dwExitCode;
FILETIME creationTime, exitTime, userFTime, sysFTime;
if( !GetProcessTimes( pi.hProcess, &creationTime, &exitTime,
&sysFTime, &userFTime ) )
throw exception( "can't get process times" );
ULONG64 processCycles;
if( !QueryProcessCycleTime( pi.hProcess, &processCycles ) )
throw exception( "can't get process cycles" );
auto ft2ts = []( const FILETIME &ft ) static -> uint64_t { return
(uint64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime; };
uint64_t
realTime = ft2ts( exitTime ) - ft2ts( creationTime ),
userTime = ft2ts( userFTime ),
sysTime = ft2ts( sysFTime );
cerr
<< "real " << formatTime( realTime ) << endl
<< "user " << formatTime( userTime ) << endl
<< "sys " << formatTime( sysTime ) << endl
<< "cylces " << formatDotted( processCycles ) << endl;
return dwExitCode;
}
catch( const exception &exc )
{
cerr << exc.what() << endl;
}
}
static const char usage[] =
"--console create new console\n"
"--detach start detached / hidden\n"
"--idle idle priority\n"
"--below below normal priority\n"
"--above above normal priority\n"
"--high high priority\n"
"--realtime realtime priority\n"
"--affintiy f CPU-affinity as hex (0x*), binary (b*) or list (e.g.
1,5-9)\n"
"--group g primary processor group\n"
"--wait wait for program to terminate\n"
"--logon u d p create process under 1. username, 2. domain and 3.
password\n"
"--no-profile don't load registry for --logon, just network-credentials\n"
"--dir d set startup directory\n"
"--times show process times (includes --wait)";
const params::state::check_fn params::state::g_checkFns[9] =
{
&checkNoProfile,
&checkLogon,
&checkDir,
&checkConsole,
&checkPriority,
&checkAffinity,
&checkGroup,
&checkWait,
&checkTimes
};
bool params::parse( int argc, const wchar_t *const *argv )
{
state st;
return st.parse( *this, argc, argv );
}
bool params::state::checkNoProfile( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--no-profile" ) != 0 )
return false;
pms.noProfile = true;
m_todo = m_todo.subspan( 1 );
return true;
}
bool params::state::checkLogon( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--logon" ) != 0 )
return false;
if( m_todo.size() < 4 )
{
m_todo = {};
m_errs.emplace_back( L"please specify username, domain and password" );
return true;
};
pms.userName = m_todo[1];
pms.domain = m_todo[2];
pms.password = m_todo[3];
m_todo = m_todo.subspan( 4 );
return true;
}
bool params::state::checkDir( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--dir" ) != 0 )
return false;
if( m_todo.size() < 2 )
{
m_todo = {};
m_errs.emplace_back( L"please supply startup direcotry" );
return true;
};
pms.startupDir = m_todo[1];
m_todo = m_todo.subspan( 2 );
return true;
}
bool params::state::checkConsole( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--console" ) == 0 )
pms.dwConsoleFlag = CREATE_NEW_CONSOLE;
else if( _wcsicmp( m_todo.front(), L"--detach" ) == 0 )
pms.dwConsoleFlag = DETACHED_PROCESS;
else
return false;
m_todo = m_todo.subspan( 1 );
return true;
}
bool params::state::checkPriority( params &pms )
{
using opt_t = pair<const wchar_t *, DWORD> ;
static const opt_t opts[] =
{
{ L"--idle", IDLE_PRIORITY_CLASS },
{ L"--below", BELOW_NORMAL_PRIORITY_CLASS },
{ L"--above", ABOVE_NORMAL_PRIORITY_CLASS },
{ L"--high", HIGH_PRIORITY_CLASS },
{ L"--realtime", REALTIME_PRIORITY_CLASS }
};
DWORD dwPrio = 0;
for( const opt_t &opt : opts )
if( _wcsicmp( m_todo.front(), opt.first ) == 0 )
{
dwPrio = opt.second;
break;
}
if( !dwPrio )
return false;
m_todo = m_todo.subspan( 1 );
pms.dwPrioFlag = dwPrio;
return true;
}
bool params::state::checkAffinity( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--affinity" ) != 0 )
return false;
if( m_todo.size() < 2 )
{
m_todo = {};
m_errs.emplace_back( L"please specify affinity" );
cerr << "" << endl;
return false;
};
DWORD_PTR dwpAff = 0;
match_results<wstring_view::iterator> match;
defer chop2( [&] { m_todo = m_todo.subspan( 2 ); } );
wstring_view svPattern( m_todo[1] );
constexpr const wchar_t
*RxHex = L"^0x([0-9a-f]+)$",
*RxBin = sizeof( DWORD_PTR ) == 8 ? L"^b((?:[01]+){1,64})$" :
L"^b((?:[01]+){1,32})$",
*RxRange = L"^([0-9]+)(?:-([0-9]+))?(,)?";
if( wregex rxHex( RxHex, regex_constants::icase ); regex_match(
svPattern.begin(), svPattern.end(), match, rxHex ) )
wistringstream( wstring( svPattern ) ) >> hex >> dwpAff;
else if( wregex rxBinary( RxBin, regex_constants::icase ); regex_match(
svPattern.begin(), svPattern.end(), match, rxBinary ) )
for( wchar_t c : wstring_view( match[1].first, match[1].second ) )
dwpAff = dwpAff << 1 | (c - '0');
else
{
defer affZero( [&] { dwpAff = 0; } );
auto it = svPattern.begin();
wregex rx( RxRange );
match_results<wstring_view::iterator> match;
for( ; regex_search( it, svPattern.end(), match, rx ); it =
match[0].second )
{
if( match[3].matched && match[3].second == svPattern.end() )
break;
unsigned from, to;
wistringstream( wstring( match[1].first, match[1].second ) ) >> from;
if( match[2].matched )
{
wistringstream( wstring( match[2].first, match[2].second ) ) >> to;
++to;
}
else
to = from + 1;
constexpr unsigned BITS = sizeof(ULONG_PTR) * 8;
if( from >= to || from >= BITS || to > BITS )
break;
constexpr DWORD_PTR ALL = -1;
DWORD_PTR dwpBits = ALL << from;
if( to < BITS )
dwpBits &= ~(ALL << to);
dwpAff |= dwpBits;
}
if( it == svPattern.end() )
affZero.disable();
}
if( !dwpAff )
{
wostringstream woss;
woss << "invalid affinity pattern: " << svPattern;
m_errs.emplace_back( woss.str() );
return true;
}
DWORD_PTR dwpProc, dwpSys;
GetProcessAffinityMask( GetCurrentProcess(), &dwpProc, &dwpSys );
if( (dwpAff &= dwpProc) )
pms.dwpAffinity = dwpAff;
return true;
}
bool params::state::checkGroup( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--group" ) != 0 )
return false;
if( m_todo.size() < 2 )
{
m_todo = {};
m_errs.emplace_back( L"please specify processor group" );
return false;
};
defer finish( [&] { m_todo = m_todo.subspan( 2 ); } );
WORD wGroups = GetActiveProcessorGroupCount();
if( !wGroups )
{
m_errs.emplace_back( L"unable to determine the active processor groups" );
return true;
}
defer invalid( [&] { m_errs.emplace_back( L"please specify valid
processor group" ); } );
wstring_view svGroup( m_todo[1] );
match_results<wstring_view::iterator> match;
wregex rxGroup( L"^[0-9]+$" );
if( !regex_match( svGroup.begin(), svGroup.end(), match, rxGroup ) )
return false;
WORD group;
wistringstream( wstring( m_todo[1] ) ) >> group;
if( group >= wGroups )
return false;
pms.wGroup = group;
invalid.disable();
return true;
}
bool params::state::checkWait( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--wait" ) != 0 )
return false;
pms.wait = true;
m_todo = m_todo.subspan( 1 );
return true;
}
bool params::state::checkTimes( params &pms )
{
if( _wcsicmp( m_todo.front(), L"--times" ) != 0 )
return false;
pms.wait = true;
pms.times = true;
m_todo = m_todo.subspan( 1 );
return true;
}
// might throw bad_alloc
static optional<WORD> setConsoleCols( WORD wAttrs );
static wstring quot( wstring_view str );
bool params::state::parse( params &pms, int argc, const wchar_t *const
*argv )
{
m_todo = span<const wchar_t *const>( argv + 1, argc - 1 );
while( m_todo.size() )
{
bool checked = false;
for( check_fn check : g_checkFns )
if( !m_todo.size() || (checked = (this->*check)( pms )) )
break;
if( !checked )
break;
}
if( m_errs.size() )
{
optional<WORD> wOldAtrs( setConsoleCols( FOREGROUND_RED ) );
defer oldCols( [&] { if( wOldAtrs ) setConsoleCols( *wOldAtrs ); } );
for( const wstring &err : m_errs )
wcout << err << endl;
return false;
}
if( !m_todo.size() )
{
cerr << endl << ::usage << endl;
return false;
}
for( const wchar_t *const &part : m_todo )
{
if( &part != &m_todo.front() )
pms.cmdLine += L" ";
pms.cmdLine += L"\"";
pms.cmdLine += part;
pms.cmdLine += L"\"";
}
return true;
}
static optional<WORD> setConsoleCols( WORD wAttrs )
{
constexpr WORD FG_CLR_MASK = FOREGROUND_RED | FOREGROUND_GREEN |
FOREGROUND_BLUE | FOREGROUND_INTENSITY;
HANDLE hStdErr = GetStdHandle( STD_ERROR_HANDLE );
if( !hStdErr || hStdErr == INVALID_HANDLE_VALUE )
return nullopt;
if( GetFileType( hStdErr ) != FILE_TYPE_CHAR )
return nullopt;
CONSOLE_SCREEN_BUFFER_INFO csbi {};
if( !GetConsoleScreenBufferInfo( hStdErr, &csbi ) )
return nullopt;
if( wAttrs == (WORD)-1 )
return csbi.wAttributes;
wAttrs = (csbi.wAttributes & ~FG_CLR_MASK) | (wAttrs & FG_CLR_MASK);
if( !SetConsoleTextAttribute( hStdErr, wAttrs ) )
return nullopt;
return csbi.wAttributes;
}
static expected<wstring, DWORD> inputPassword()
{
cout.flush(), wcout.flush();
constexpr auto *err = +[] static { return unexpected( GetLastError() ); };
HANDLE hStdIn, hStdOut;
if( !(hStdIn = GetStdHandle( STD_INPUT_HANDLE )) )
return err();
if( !(hStdOut = GetStdHandle( STD_OUTPUT_HANDLE )) )
return err();
DWORD dwOldConsoleMode;
if( !GetConsoleMode( hStdIn, &dwOldConsoleMode ) )
return err();
if( !SetConsoleMode( hStdIn, dwOldConsoleMode & ~(ENABLE_ECHO_INPUT |
ENABLE_LINE_INPUT) ) )
return err();
defer revert( [&] { SetConsoleMode( hStdIn, dwOldConsoleMode ); } );
vector<COORD> coords;
wstring pass;
for( ; ; )
{
wchar_t ch;
if( DWORD dwRead; !ReadConsoleW( hStdIn, &ch, 1, &dwRead, nullptr ) ||
!dwRead )
return err();
if( ch == L'\r' )
return pass;
auto writeConsole = [&]( wchar_t ch )
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if( !GetConsoleScreenBufferInfo( hStdOut, &csbi ) )
return false;
coords.emplace_back( csbi.dwCursorPosition );
DWORD dwWritten;
return WriteConsoleW( hStdOut, &ch, 1, &dwWritten, nullptr ) &&
dwWritten == 1;
};
if( ch != L'\b' )
{
pass += ch;
if( !writeConsole( L'*' ) )
return err();
continue;
}
if( !pass.length() )
continue;
pass.pop_back();
auto back = [&]()
{
if( !SetConsoleCursorPosition( hStdOut, coords.back() ) )
return false;
coords.pop_back();
return true;
};
if( !back() || !writeConsole( L' ' ) || !back() )
return err();
}
return pass;
}
static string formatTime( uint64_t t )
{
constexpr auto MS = 10'000u;
t = (t + MS / 2) / MS;
uint16_t ms = t % 1'000; t /= 1'000;
uint8_t secs = t % 60; t /= 60;
uint8_t mins = t % 60; t /= 60;
uint32_t hours = (uint32_t)t;
ostringstream oss;
if( hours )
oss << hours << "h" << ":";
if( hours || mins )
oss << mins << "m" << ":";
oss << (int)secs;
if( ms )
oss << "." << setw( 3 ) << setfill( '0' ) << ms;
oss << "s";
return oss.str();
}
static string formatDotted( uintmax_t value )
{
ostringstream oss;
oss << value;
string_view svDigits( oss.view() );
auto pDigits = svDigits.begin();
size_t
digLen = svDigits.length(),
dots = (digLen - 1) / 3,
head = digLen - 3 * dots;
string dotted( digLen + dots, 0 );
auto pDotted = dotted.begin();
pDotted = copy( pDigits, pDigits + head, pDotted );
for( ; pDotted != dotted.end(); pDigits += 3 )
{
*pDotted++ = L'.';
pDotted = copy( pDigits, pDigits + 3, pDotted );
}
return dotted;
}
[toc] | [prev] | [next] | [standalone]
| From | Paul <nospam@needed.invalid> |
|---|---|
| Date | 2026-06-27 07:20 -0400 |
| Message-ID | <111oblh$2r3ac$1@paganini.bofh.team> |
| In reply to | #400078 |
On Tue, 6/16/2026 3:39 AM, Lawrence D’Oliveiro wrote: > On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote: > >> I've written a tool called "bg" to combine Windows' runas with >> start. > > Sort of a Windows answer to systemd? Somebody is already working on that > <https://github.com/Jamesits/SvcGuest>. > >> One parameter is the affinity-mask for the processors which the >> started program is attached to. > > They haven’t yet added that capability (which systemd has). Perhaps > you could contribute code ... > Windows has had third-party launch tools for some time. One of the situations where this was encountered, was some games would not "tolerate" dual core computers, and the EXE cooked up at the time could fix that for you, without resorting to Task Manager to do it from there. You can see here, that generally speaking, there is a way to do it. https://superuser.com/questions/309617/how-to-limit-a-process-to-a-single-cpu-core And this is the utility I was thinking of, RunFirst. What this does, is it doesn't provide arbitrary single-core affinity, it's for running games on CPU0, and relying upon the scheduler to move other tasks to CPU1. The purpose of RunFirst, is to prevent games from crashing that do not handle the CPU core issue properly. It makes the game "think" it is on a single core CPU. If the game were to check, it reads CPU0, and the game is then satisfied that not only does it have one core, the one core is numbered CPU0. https://www.vogons.org/viewtopic.php?t=31541 C:\Windows\System32\RunFirst.exe "C:\Program Files\GOG.com\Divine Divinity\Div.exe" Paul
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2026-06-27 21:28 +0300 |
| Message-ID | <20260627212842.00003a0a@yahoo.com> |
| In reply to | #400258 |
On Sat, 27 Jun 2026 07:20:17 -0400 Paul <nospam@needed.invalid> wrote: > On Tue, 6/16/2026 3:39 AM, Lawrence D’Oliveiro wrote: > > On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote: > > > >> I've written a tool called "bg" to combine Windows' runas with > >> start. > > > > Sort of a Windows answer to systemd? Somebody is already working on > > that <https://github.com/Jamesits/SvcGuest>. > > > >> One parameter is the affinity-mask for the processors which the > >> started program is attached to. > > > > They haven’t yet added that capability (which systemd has). Perhaps > > you could contribute code ... > > > > Windows has had third-party launch tools for some time. > One of the situations where this was encountered, was > some games would not "tolerate" dual core computers, and > the EXE cooked up at the time could fix that for you, > without resorting to Task Manager to do it from there. > > You can see here, that generally speaking, there is a way to do it. > > https://superuser.com/questions/309617/how-to-limit-a-process-to-a-single-cpu-core > > And this is the utility I was thinking of, RunFirst. What this does, > is it doesn't provide arbitrary single-core affinity, it's for > running games on CPU0, and relying upon the scheduler to move other > tasks to CPU1. The purpose of RunFirst, is to prevent games from > crashing that do not handle the CPU core issue properly. It makes the > game "think" it is on a single core CPU. If the game were to check, > it reads CPU0, and the game is then satisfied that not only does it > have one core, the one core is numbered CPU0. > > https://www.vogons.org/viewtopic.php?t=31541 > > C:\Windows\System32\RunFirst.exe "C:\Program > Files\GOG.com\Divine Divinity\Div.exe" > > Paul How does it differ from "start /affinity 1 div.exe" ?
[toc] | [prev] | [next] | [standalone]
| From | Paul <nospam@needed.invalid> |
|---|---|
| Date | 2026-06-27 16:53 -0400 |
| Message-ID | <111pd93$2tjn0$1@paganini.bofh.team> |
| In reply to | #400261 |
On Sat, 6/27/2026 2:28 PM, Michael S wrote: > On Sat, 27 Jun 2026 07:20:17 -0400 > Paul <nospam@needed.invalid> wrote: > >> On Tue, 6/16/2026 3:39 AM, Lawrence D’Oliveiro wrote: >>> On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote: >>> >>>> I've written a tool called "bg" to combine Windows' runas with >>>> start. >>> >>> Sort of a Windows answer to systemd? Somebody is already working on >>> that <https://github.com/Jamesits/SvcGuest>. >>> >>>> One parameter is the affinity-mask for the processors which the >>>> started program is attached to. >>> >>> They haven’t yet added that capability (which systemd has). Perhaps >>> you could contribute code ... >>> >> >> Windows has had third-party launch tools for some time. >> One of the situations where this was encountered, was >> some games would not "tolerate" dual core computers, and >> the EXE cooked up at the time could fix that for you, >> without resorting to Task Manager to do it from there. >> >> You can see here, that generally speaking, there is a way to do it. >> >> https://superuser.com/questions/309617/how-to-limit-a-process-to-a-single-cpu-core >> >> And this is the utility I was thinking of, RunFirst. What this does, >> is it doesn't provide arbitrary single-core affinity, it's for >> running games on CPU0, and relying upon the scheduler to move other >> tasks to CPU1. The purpose of RunFirst, is to prevent games from >> crashing that do not handle the CPU core issue properly. It makes the >> game "think" it is on a single core CPU. If the game were to check, >> it reads CPU0, and the game is then satisfied that not only does it >> have one core, the one core is numbered CPU0. >> >> https://www.vogons.org/viewtopic.php?t=31541 >> >> C:\Windows\System32\RunFirst.exe "C:\Program >> Files\GOG.com\Divine Divinity\Div.exe" >> >> Paul > > How does it differ from "start /affinity 1 div.exe" ? Runfirst was written years ago, like maybe WinXP era. Some of the other (convenience) methods, did not exist at the time. Paul
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2026-06-28 02:07 +0300 |
| Message-ID | <20260628020729.00005e20@yahoo.com> |
| In reply to | #400263 |
On Sat, 27 Jun 2026 16:53:56 -0400 Paul <nospam@needed.invalid> wrote: > On Sat, 6/27/2026 2:28 PM, Michael S wrote: > > On Sat, 27 Jun 2026 07:20:17 -0400 > > Paul <nospam@needed.invalid> wrote: > > > >> On Tue, 6/16/2026 3:39 AM, Lawrence D’Oliveiro wrote: > >>> On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote: > >>> > >>>> I've written a tool called "bg" to combine Windows' runas with > >>>> start. > >>> > >>> Sort of a Windows answer to systemd? Somebody is already working > >>> on that <https://github.com/Jamesits/SvcGuest>. > >>> > >>>> One parameter is the affinity-mask for the processors which the > >>>> started program is attached to. > >>> > >>> They haven’t yet added that capability (which systemd has). > >>> Perhaps you could contribute code ... > >>> > >> > >> Windows has had third-party launch tools for some time. > >> One of the situations where this was encountered, was > >> some games would not "tolerate" dual core computers, and > >> the EXE cooked up at the time could fix that for you, > >> without resorting to Task Manager to do it from there. > >> > >> You can see here, that generally speaking, there is a way to do it. > >> > >> https://superuser.com/questions/309617/how-to-limit-a-process-to-a-single-cpu-core > >> > >> And this is the utility I was thinking of, RunFirst. What this > >> does, is it doesn't provide arbitrary single-core affinity, it's > >> for running games on CPU0, and relying upon the scheduler to move > >> other tasks to CPU1. The purpose of RunFirst, is to prevent games > >> from crashing that do not handle the CPU core issue properly. It > >> makes the game "think" it is on a single core CPU. If the game > >> were to check, it reads CPU0, and the game is then satisfied that > >> not only does it have one core, the one core is numbered CPU0. > >> > >> https://www.vogons.org/viewtopic.php?t=31541 > >> > >> C:\Windows\System32\RunFirst.exe "C:\Program > >> Files\GOG.com\Divine Divinity\Div.exe" > >> > >> Paul > > > > How does it differ from "start /affinity 1 div.exe" ? > > Runfirst was written years ago, like maybe WinXP era. > Some of the other (convenience) methods, did not exist at the time. > > Paul > > I think that 'start /affinity' existed in WinXp and I would be surprised if it didn't exist much earlier.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2026-06-27 22:02 -0700 |
| Message-ID | <111q9t2$3dfo9$1@dont-email.me> |
| In reply to | #400265 |
On 6/27/2026 4:07 PM, Michael S wrote: > On Sat, 27 Jun 2026 16:53:56 -0400 > Paul <nospam@needed.invalid> wrote: > >> On Sat, 6/27/2026 2:28 PM, Michael S wrote: >>> On Sat, 27 Jun 2026 07:20:17 -0400 >>> Paul <nospam@needed.invalid> wrote: >>> >>>> On Tue, 6/16/2026 3:39 AM, Lawrence D’Oliveiro wrote: >>>>> On Mon, 15 Jun 2026 11:10:46 +0200, Bonita Montero wrote: >>>>> >>>>>> I've written a tool called "bg" to combine Windows' runas with >>>>>> start. >>>>> >>>>> Sort of a Windows answer to systemd? Somebody is already working >>>>> on that <https://github.com/Jamesits/SvcGuest>. >>>>> >>>>>> One parameter is the affinity-mask for the processors which the >>>>>> started program is attached to. >>>>> >>>>> They haven’t yet added that capability (which systemd has). >>>>> Perhaps you could contribute code ... >>>>> >>>> >>>> Windows has had third-party launch tools for some time. >>>> One of the situations where this was encountered, was >>>> some games would not "tolerate" dual core computers, and >>>> the EXE cooked up at the time could fix that for you, >>>> without resorting to Task Manager to do it from there. >>>> >>>> You can see here, that generally speaking, there is a way to do it. >>>> >>>> https://superuser.com/questions/309617/how-to-limit-a-process-to-a-single-cpu-core >>>> >>>> And this is the utility I was thinking of, RunFirst. What this >>>> does, is it doesn't provide arbitrary single-core affinity, it's >>>> for running games on CPU0, and relying upon the scheduler to move >>>> other tasks to CPU1. The purpose of RunFirst, is to prevent games >>>> from crashing that do not handle the CPU core issue properly. It >>>> makes the game "think" it is on a single core CPU. If the game >>>> were to check, it reads CPU0, and the game is then satisfied that >>>> not only does it have one core, the one core is numbered CPU0. >>>> >>>> https://www.vogons.org/viewtopic.php?t=31541 >>>> >>>> C:\Windows\System32\RunFirst.exe "C:\Program >>>> Files\GOG.com\Divine Divinity\Div.exe" >>>> >>>> Paul >>> >>> How does it differ from "start /affinity 1 div.exe" ? >> >> Runfirst was written years ago, like maybe WinXP era. >> Some of the other (convenience) methods, did not exist at the time. >> >> Paul >> >> > > > I think that 'start /affinity' existed in WinXp and I would be surprised > if it didn't exist much earlier. > > > > > Win XP had support for hyperthreads iirc?
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web