JobObject实现对进程进行内存和运行时间限制

最近在研究oj系统,查过网上的解决方案,大致分为两种:

一种是基于Java虚拟机的解决方案,让编译好的程序运行在java虚拟机里面,通过对虚拟机的限制保障时空有效性和系统安全性;

第二种是基于linux系统的方案,通过内置的系统函数设置程序可用资源以及通过限制用户运行此程序以保障系统安全性.

实际情况是希望在windows下实现oj系统,而且对jvm无爱,遂研究下通过windows的一些内核机制实现此目的.

根据上面的第二种解决方案后查阅MSDN及相关资料后得知windows下没有设置程序可用资源的函数,只有通过JobObject创建一个工作对象以限制其运行.关于系统安全性方面则可以采用其他低权限账户运行(暂时没有找到更好的解决方案,沙箱或许可行,但是工程过于庞大.),这里不做过多介绍,详见CreateProcessAsUser,后续博文里可能会更详细的介绍.

接下来进入正题,通过JobObject创建新的工作对象大致经过如下步骤:

  1. 通过CreateJobObject创建一个工作对象;
  2. 通过SetInformationJobObject设置工作对象的参数,详见MSDN;
  3. 以CREATE_SUSPENDED方式启动进程,通过CreateProcessAsUser或者CreateProcess函数,可能还有其他函数,未做研究.
  4. 通过AssignProcessToJobObject将工作对象应用到指定进程中.
  5. 通过ResumeThread恢复已暂停的进程.
  6. 通过WaitForSingleObject等待正在运行的工作对象,设置好允许使用时间.
  7. 通过QueryInformationJobObject获取工作对象的最终状态.运行程序的退出状态可以通过GetExitCodeProcess获取.
  8. 扫尾工作(必须使用TerminateJobObject结束当前的工作对象,因为工作对象即便设置了PerProcessUserTimeLimit也无法使程序在超时后退出,没有研究原因).

以下是一段Demo代码:

#define _WIN32_WINNT 0x0500
#include "stdafx.h"
#include "windows.h"
#include "winbase.h"
 
int main(int argc, char* argv[])
{
  LPCWSTR path=L"C:\\Time.exe";
 
  HANDLE Job=CreateJobObject(NULL,NULL);
  if(Job!=NULL)
  {
    printf("CreateJobObject   [OK]\n");
    JOBOBJECT_BASIC_LIMIT_INFORMATION Job_Limit;
    memset(&Job_Limit,0,sizeof(Job_Limit));
    Job_Limit.LimitFlags=JOB_OBJECT_LIMIT_WORKINGSET|JOB_OBJECT_LIMIT_PROCESS_TIME;
    Job_Limit.MinimumWorkingSetSize=1;
    Job_Limit.MaximumWorkingSetSize=1024*1024*10;//单位比特
    Job_Limit.PerProcessUserTimeLimit.QuadPart=10000*1000*1;//单位100纳秒
    if(SetInformationJobObject(Job,JobObjectBasicLimitInformation,&Job_Limit,sizeof(Job_Limit)))
    {
      printf("SetInformationJobObject   [OK]\n");
      STARTUPINFO pStaus = {sizeof(pStaus)};
      PROCESS_INFORMATION pInfo;
      if(CreateProcess(path,NULL,NULL,NULL,FALSE,CREATE_NEW_CONSOLE | CREATE_SUSPENDED,NULL,NULL,&pStaus,&pInfo))
      {
        printf("CreateProcess   [OK]\n");
 
        if(AssignProcessToJobObject(Job,pInfo.hProcess))
        {
          printf("AssignProcessToJobObject    [OK]\n");
          ResumeThread(pInfo.hThread);
          CloseHandle(pInfo.hThread);
 
          DWORD WaitRe = WaitForSingleObject(Job,1000);
          if(WaitRe!=WAIT_FAILED)
          {
            printf("WaitForSingleObject   [OK]\n");
            JOBOBJECT_EXTENDED_LIMIT_INFORMATION lpJobObjectInfo;
            DWORD lpReturnLength;
            if(QueryInformationJobObject(Job,JobObjectExtendedLimitInformation,&lpJobObjectInfo,sizeof(lpJobObjectInfo),&lpReturnLength))
            {
              printf("Memory:%dKb\n",lpJobObjectInfo.PeakProcessMemoryUsed/1024);
              DWORD ExitCode=0;
              //TerminateJobObject(Job,0);
              if(GetExitCodeProcess(pInfo.hProcess,&ExitCode))
              {
                printf("ExitCode:%d\n",ExitCode);
              }
            }
          }
          else
          {
            printf("WaitForSingleObject   [Error:%d]\n",GetLastError());
          }
          TerminateJobObject(Job,0);//exit
          CloseHandle(pInfo.hProcess);
          CloseHandle(Job);
        }
        else
        {
          TerminateProcess(pInfo.hProcess,0);//Change
          printf("AssignProcessToJobObject    [Error:%d]\n",GetLastError());
        }
      }
      else
      {
        printf("CreateProcess   [Error:%d]\n",GetLastError());
      }
    }
    else
    {
      printf("SetInformationJobObject   [Error:%d]\n",GetLastError());
    }
  }
  else
  {
    printf("CreateJobObject   [Error:%d]\n",GetLastError());
  }
  system("pause");
  return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据和云

时过境迁:Oracle跨平台迁移之XTTS方案与实践

作者简介 ? 谢金融 云和恩墨东区交付部 Oracle 工程师,多年来从事 Oracle 第三方服务,曾服务过金融、制造业、物流、政府等许多行业的客户,精通数据...

50010
来自专栏java系列博客

pl/sql导入excel到oracle表

2017
来自专栏逸鹏说道

在不动用sp_configure的情况下,如何 =》去掉列的自增长,并保留原数据

应用场景:权限不够(只是某个用户,权限很低,不能使用sp_configure) ? 执行 ? 附录: update BackupShopMenu set Tem...

33914
来自专栏大宽宽的碎碎念

怎么避免MYSQL误删除避免混淆开发环境的DB和生产环境的DB用事务保护使用安全更新模式对DROP和TRUNCATE慎之又慎最终的招数最终的话

34513
来自专栏杨建荣的学习笔记

物化视图刷新结合ADG的尝试 (r8笔记第47天)

最近开发提了几个需求,需要把几个线上的分布式的表整合到统计系统中方便统计,看来分久必合,合久必分,当时的分开考虑,肯定没有想到以后会整合起来,这 可对我们是一些...

35610
来自专栏智能大石头

每天4亿行SQLite订单大数据测试(源码)

SQLite单表4亿订单,大数据测试 SQLite作为嵌入式数据库的翘楚,广受欢迎! 新生命团队自2010年以来,投入大量精力对SQLite进行学习研究,成功应...

4056
来自专栏PingCAP的专栏

TiDB 2.1 GA Release Notes

2018 年 11 月 30 日,TiDB 发布 2.1 GA 版。相比 2.0 版本,该版本对系统稳定性、性能、兼容性、易用性做了大量改进。

390
来自专栏量化投资与机器学习

战斗民族开源神器ClickHouse:一款适合于构建量化回测研究系统的高性能列式数据库(二)

编辑部原创 编译:wally21st、 西西 未经允许,不得转载 Tutorial 对于一些私募、投资机构和个人来说,量化投资研究、回测离不开数据的支持。当数据...

1.6K6
来自专栏数据和云

忘记SQL Server 管理员密码不可怕,学会这招就够了

作者 | 邹建,资深数据库专家,精通各项 SQL Server 技术,具有丰富的管理、维护、优化能力以及业务应用经验。他一直热心于技术知识的分享、传播,持续活跃...

1343
来自专栏MongoDB中文社区

MongoDB事务模型分析

在了解写操作的事务性之前,需要先了解mongo层的每一个table,是如何与wiredtiger层的table(btree)对应的。mongo层一个最简单的ta...

992

扫码关注云+社区