一个进程可以在主内存中的0页开始执行吗?

我正在阅读一本关于操作系统(Galvin )的书。 它解释了需求分页

在极端情况下, 我们可以开始执行一个没有页面内存的进程 。 当操作系统将指令指针设置为处于非内存驻留页面上的进程的第一条指令时,该进程立即为页面错误。

我的问题是如何操作系统可以设置一个进程,甚至没有单个页面在内存中的指令指针(因为指令指针中的地址不能是一个光盘或辅助内存地址,它必须是一个主内存地址,但0页的手段没有什么是在记忆中)。

这就是虚拟内存。 这意味着在已知和不变的逻辑地址和瞬态的物理地址之间有短暂的映射。 正常的处理级别纯粹在逻辑地址中工作,而不必知道物理上发生了什么。

因此,操作系统会例如说二进制A在地址N上是逻辑上可用的。然后它将在虚拟地图中标记覆盖N到N +(二进制大小)的页面当前是故障。 将PC设置为N(或任何入口点)后,一旦CPU尝试从PC读取,MMU就会触发故障。 在这一点上,分页机制将抓住故障,并做平常的事情。

注释行中出现错误“0:找不到命令”

帮帮我! 运行我的脚本后,我得到错误A1.sh:行205:0:命令未find。

令我感到困惑的是第205行是一个评论! 我试过编辑它,但仍然在同一行上得到一个错误。 我所有的行结束都是LF。

下面是编辑后的代码块,现在是第205行:

if `doesBookExist "$title" "$author"` 

全部代码:

 if [[ bookExist -gt 0 ]] then # get title from actual book (in case title input has bad case) actualTitle=`cut -d ':' -f 1 BookDB.txt | grep -i "^$title$"` sed -i "/^$title:$author.*$/Id" $FILENAME if `doesBookExist "$title" "$author"` then title=`echo "$title" | tr "@" ":"` echo echo "Book title '$actualTitle' could not be removed!" else title=`echo "$title" | tr "@" ":"` echo echo "Book title '$actualTitle' removed successfully!" fi else echo echo 'Book does not exist!' fi 

任何帮助表示赞赏!

在bash中, if期望一个命令作为第二个参数。 你给它的是你的命令替换的返回码,它是0 – 不是一个合法的命令。

所以你不需要这样做:

 if `doesBookExist "$title" "$author"` 

但是这只是:

 if doesBookExist "$title" "$author" 

顺便说一句: $(somecommand someargs)是命令替换的首选方式 – 当你需要时 – 因为它可以任意嵌套。

反引号执行命令替换 。 它看起来好像在你尝试运行命令替换之后

  if 0 then ... fi 

这解释了错误信息。 但是你想比较输出到一个字符串。 这是最灵活的一个案例陈述:

  case $(doesBookExist "$title" "$author") in (0) # if it is 0 ;; (1) # if it is 1 ;; esac 

额外的0在窗口浮动打印

我有一个程序,显示不同的打印(在Windows上额外的0),我试图使它与Linux相同。 在使用Visual Studio 2012的窗口上。 在linux上使用g ++ v4.8.3

任何sugegstion。

我创build了一个小程序来展示我正面临的问题

#include "stdafx.h" #include <stdio.h> int main() { float f = -1e-14; printf("\n\n \t Lets print the float value -1e-14 as [%9.3g] \n\n\n\n",f); return 0; } 

在linux上:

 /home/mag>./a.out Lets print the float value -1e-14 as [ -1e-14] 

在窗口上:(注意在-1e-014中多出0)

  Lets print the float value -1e-14 as [ -1e-014] 

我试图让它一样的原因是因为我debugging一些输出从Windows和Linux和输出的Windows和Linux之间的巨大差异是由于上述的问题,我错过了重要的差异,因为这些。

首先调用_set_output_format(_TWO_DIGIT_EXPONENT) ,使printf()在VS2012中使用两位指数。

睡眠(0)? 一致的时间保持在代码?

现在我正在加载一个文件,然后使用gettimeofday和tv_usec跟踪CPU时间

我的结果各不相同,我得到250到280,但有时候是300或500。 我写了睡觉和睡觉(0)和(1)没有成功。 时间仍然很大。 我认为睡眠(1)(在Linux秒,而不是睡在毫秒窗)将解决它。 我如何以更一致的方式跟踪时间进行testing? 也许我应该等到我有更大的testing数据和更复杂的代码才能开始测量?

目前在Linux(以及一般的POSIX)上推荐使用高时间接口的接口是clock_gettime。 看手册页。

clock_gettime(CLOCK_REALTIME, struct timespec *tp) // for wall-clock time clock_gettime(CLOCK_PROCESS_CPUTIME_ID, struct timespec *tp) // for CPU time 

但请阅读手册页。 请注意,你需要链接-lrt,因为POSIX是这样说的,我想。 也许为了避免-lc中的符号冲突,对于定义自己的clock_gettime的旧程序? 但动态库使用弱符号…

最好的睡眠功能是睡眠。 它不会像信号或垃圾一样混乱。 它被定义为只是睡觉,没有任何其他副作用。 它告诉你,如果你早早醒来(例如从信号),所以你不一定要调用另一个时间功能。

无论如何,你将很难测试一个涉及系统调用的简短代码。 变化的机会是巨大的。 例如,调度员可能会决定其他一些工作需要做的事情(如果你的流程刚刚开始,你不会用完你的时间片)。 CPU缓存(L2和TLB)很容易实现。

如果你有一个多核心机器和你正在优化的代码的单线程基准测试,你可以给它的实时优先级固定到你的一个核心。 确保你选择了不处理中断的核心,否则你的键盘(以及其他的)将被锁定,直到完成。 使用taskset(固定到一个CPU)和chrt(用于设置实时prio)。 看到这个邮件我发送给gmp-devel与这个技巧: http : //gmplib.org/list-archives/gmp-devel/2008-March/000789.html

噢,对于最精确的时机,你可以自己使用rdtsc(在x86 / amd64上)。 如果你没有任何其他系统调用,那么这不是一个坏主意。 抓住一个基准框架,把你的功能。 GMP有一个相当不错的。 但是,对于不在GMP中并称为mpn_whatever的基准测试功能,可能并不适用。 我不记得了,值得一看。

你想测量加载文件需要多长时间? 通常如果你测试了一些已经很快(亚秒)的代码的性能,那么你会希望多次重复相同的代码(比如说一千或者一百万),然后重复一遍,然后总时间除以迭代次数。

说了这么多,我不太清楚你正在使用sleep()。 你能举一个你打算做什么的例子吗?

我建议将该代码放在for循环中。 运行1000或10000次以上。 如果你只做了几个指示,那么这个问题会有帮助。

大数据集当然也有帮助。

睡眠将从CPU中去除你的线程。 它不准确地计算时间。

睡0有特别的意义?

我在我的一个客户项目中看到很多sleep 0用法sleep 0

代码看起来像这样。

 while true ... ... sleep 0 end 

通过阅读这样的一些答案,似乎sleep 0有一些意义。

我现在想知道的是,在时间片0期间调度要运行的其他线程(如果它们正在等待运行的话)是像Ruby或Python这样的lang VM的工作,或者它是内核的工作。

为了让Ruby VM能够像在上面的链接中提到的那样尊重sleep 0

是的,出于几个原因,首先,(mri)ruby线程是使用附加的GVL锁定在本地线程周围的包装。

基本上,当你调用sleep时,ruby正在做的是调用底层的,本地的,依赖于平台的睡眠,并释放GVL,以便其他正在运行的线程可以获取它。 所以sleep(0)同时产生到可能正在等待执行的其他本地线程,以及释放当前线程在GVL上的保持,否则将保持Ruby VM执行。

下面是一个简要的简要说明,你可以从mri源码看到这个:

  1. 我们从https://github.com/ruby/ruby/blob/trunk/process.c#L7542得到内核睡眠的定义,我们看到它是在函&#x6570;rb_f_sleep
  2. 接下来我们去rb_f_sleep ,看看在一个参数的情况下,它会调用rb_thread_wait_for
  3. rb_thread_wait_for定义,我们看到一个调用sleep_timeval
  4. sleep_timeval调用了native_sleep
  5. native_sleep是依赖于平台的,分别在thread_pthread.c和thread_win32.c中用于posix和windows系统。 无论哪种情况,我们GVL_UNLOCK_BEGIN 在这里和这里看到对GVL_UNLOCK_BEGIN调用

编辑

更确切地说:

视窗:

native_sleep的windows实现使用WaitForMultipleObjects ,它确实产生了剩余的时间片,请参阅: WaitForSingleObject是否放弃线程的时间片?

POSIX:

posix实现使用pthread_cond_timedwait ,它阻止当前正在运行的线程。

无论哪种方式,这里要注意的是,Ruby线程使用操作系统的底层线程阻塞机制,并释放任何调用睡眠的GVL,以允许其他线程控制。

拉链瘪了0%? 为什么不压缩?

我试图压缩包含4个大文件的文件夹的内容,非常非常相似。 所以我期望的大小减less。

这是我在linux / fedora上使用的命令

zip -9 myarchive.zip -r myfolder -P mypassword 

我得到的回应是:

 adding: myfolder/ (stored 0%) adding: myfolder/Program1.exe (deflated 0%) adding: myfolder/Program2.exe (deflated 0%) adding: myfolder/Program3.exe (deflated 0%) adding: myfolder/Program4.exe (deflated 0%) 

然后我得到与我的原始文件夹大小相同的存档。

似乎没有任何压缩发生。 为什么?

tar + gzip不同, zip为每个文件使用一个新的压缩表,所以即使这四个文件是相同的,它也会尝试单独压缩每个文件。

从技术上来说, tar也会看到每个文件,但是它们将它们串联起来成为gzip一个长输入,所以压缩步骤在一个巨大的输入上工作,这就是为什么tar + gzip通常比zip产生更小的结果。

问题是为什么你的exe文件不能被压缩。 exe文件通常包含大量的易于压缩的数据,所以它们应该缩小(“缩小”)至少30%。 也许这些文件被加密或混淆; 这些过程使结果难以压缩。

一些文件不能被压缩,特别是如果它们的熵很高的话。 当字节的统计分布是偶数的时候(例如,当字节0出现的频率与字节1一样多时,会发生这种情况)。 这发生在已经压缩的内容上。 一些视频或音频格式属于该类别。

亚伦是对的。 根据WikipediaZIP格式在压缩之前压缩,所以不同文件之间的相似性不利于压缩。

你真的想压缩.exe文件吗? 不知何故,我怀疑这是你的实际文件类型。

请参阅http://en.wikipedia.org/wiki/ZIP_(file_format)#Advantages_and_disadvantages

贬值0%意味着它试图压缩,但实际上没有压缩。 如上所述,zip格式不能利用不同条目之间的相似性。 tar + gzip可以,但即使如此,只有相似性最终不超过32K字节彼此。 其他格式可以利用更长距离的相似性,如xz。

未压缩的可执行文件压缩30%到50%是正常的,这意味着你的可执行文件要么被a)像UPX那样压缩,b)它们是自解压缩的压缩数据,其中解压缩器存储在压缩数据之前,c)它们是非常短的可执行文件,具有大量的压缩数据,或者d)它们大多被加密。

为什么写入缓冲区填充的缓冲区比写入0的缓冲区快?

不pipe存储器1的现有内容如何,​​我都希望写入char *缓冲区的时间相同。 你不是吗?

然而,在缩小基准的不一致性的同时,我发现了一个显然不是真实的案例。 包含全零的缓冲区在性能上与用42填充的缓冲区有很大不同。

从graphics上看,这看起来像(详情如下):

缓冲区写入时间

这是我用来产生上述3的代码:

 #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <string.h> #include <time.h> volatile char *sink; void process(char *buf, size_t len) { clock_t start = clock(); for (size_t i = 0; i < len; i += 678) buf[i] = 'z'; printf("Processing took %lu μs\n", 1000000UL * (clock() - start) / CLOCKS_PER_SEC); sink = buf; } int main(int argc, char** argv) { int total = 0; int memset42 = argc > 1 && !strcmp(argv[1], "42"); for (int i=0; i < 5; i++) { char *buf = (char *)malloc(BUF_SIZE); if (memset42) memset(buf, 42, BUF_SIZE); else memset(buf, 0, BUF_SIZE); process(buf, BUF_SIZE); } return EXIT_SUCCESS; } 

我在我的Linux机器上编译它,如:

  gcc -O2 buffer_weirdness.cpp -o buffer_weirdness 

…当我用零缓冲区运行版本时,我得到:

 ./buffer_weirdness zero Processing took 12952 μs Processing took 403522 μs Processing took 626859 μs Processing took 626965 μs Processing took 627109 μs 

注意第一次迭代很快 ,而剩下的迭代花费的时间可能要长50倍

当缓冲区首先被填充42 ,处理总是快速的:

 ./buffer_weirdness 42 Processing took 12892 μs Processing took 13500 μs Processing took 13482 μs Processing took 12965 μs Processing took 13121 μs 

行为取决于BUF_SIZE(上面例子中的1GB) – 更大的尺寸更可能显示问题,也取决于当前的主机状态。 如果我把主机单独留出一段时间,慢速迭代可能需要60,000μs,而不是60 000μs,因此速度要快10倍,但仍比快速处理时间慢5倍。 最终时代会回到完全缓慢的行为。

行为还至less部分取决于透明的巨大页面 – 如果我禁用它们2 ,缓慢迭代的性能提高约3倍,而快速迭代不变。

最后需要说明的是,进程的运行时间比简单地对进程进行计时要近得多(实际上,零填充,THPclosures版本比其他的快了大约两倍,这大致相同)。

这里发生了什么?


1除了一些非常不寻常的优化之外,比如编译器了解缓冲区已经包含的什么值,并且删除了相同值的写入,这在这里没有发生。

2 sudo sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"

3这是原始基准的蒸馏版本。 是的,我泄漏了分配,克服了它 – 这导致了一个更简洁的例子。 原来的例子没有泄漏。 事实上,当你不泄漏分配时,行为会发生变化:可能是因为malloc可以重新使用该区域来进行下一次分配,而不是向操作系统请求更多的内存。

这似乎很难重现,所以它可能是特定的编译器/ libc。

我最好的猜测在这里:

当你调用malloc ,你将内存映射到你的进程空间 ,这并不意味着操作系统已经从它的可用内存池中获取了必要的页面,但是它只是把一些表项添加到了一些表中。

现在,当你尝试访问那里的内存时,你的CPU / MMU会引发一个错误 – 操作系统可以捕获这个错误,并检查该地址是否属于“已经在内存空间中,但还没有真正分配给处理”。 如果是这样的话,必要的空闲内存被找到并映射到你的进程的内存空间。

现在,现代操作系统通常有一个内置的选项来在(重新)使用之前“清零”页面。 如果这样做, memset(,0,)操作变得不必要。 在POSIX系统的情况下,如果使用calloc而不是malloc ,内存将被清零。

换句话说,你的编译器可能已经注意到了,并且当你的操作系统支持时,完全省略了memset(,0,) 。 这意味着,当您写入process()的页面时,这是他们访问的第一个时刻 – 并触发操作系统的“即时页面映射”机制。

memset(,42,)当然可以不被优化,所以在这种情况下,页面实际上是预先分配的,你不会看到在process()函数中花费的时间。

你应该使用/usr/bin/time来实际比较整个执行时间与process的时间 – 我的怀疑意味着在process保存的时间实际上花费在main内核上,可能在内核上下文中。

更新 :测试与优秀的Godbolt编译器资源管理器 :是的,与-O2-O3 ,现代gcc简单地省略零memsetting(或者,而是简单地融合到calloc ,这是malloc零):

 #include <cstdlib> #include <cstring> int main(int argc, char ** argv) { char *p = (char*)malloc(10000); if(argc>2) { memset(p,42,10000); } else { memset(p,0,10000); } return (int)p[190]; // had to add this for the compiler to **not** completely remove all the function body, since it has no effect at all. } 

成为gcc6.3上的x86_64

 main: // store frame state push rbx mov esi, 1 // put argc in ebx mov ebx, edi // Setting up call to calloc (== malloc with internal zeroing) mov edi, 10000 call calloc // ebx (==argc) compared to 2 ? cmp ebx, 2 mov rcx, rax // jump on less/equal to .L2 jle .L2 // if(argc > 2): // set up call to memset mov edx, 10000 mov esi, 42 mov rdi, rax call memset mov rcx, rax .L2: //else case //notice the distinct lack of memset here! // move the value at position rcx (==p)+190 into the "return" register movsx eax, BYTE PTR [rcx+190] //restore frame pop rbx //return ret 

顺便说一句,如果你删除return p[190]

  } return 0; } 

那么编译器没有理由保留函数体 – 它的返回值在编译时很容易确定,并且没有副作用。 整个程序然后编译

 main: xor eax, eax ret 

请注意, A xor A0

为什么窗口中第一行文件的第一个字符是0?

所以我正在阅读Java中的纯文本文件,我想确定哪些行以“abc”开头。 我做了以下几点:

字符集字符集= StandardCharsets.UTF_8;
 BufferedReader br = Files.newBufferedReader(file.toAbsolutePath(),charset);
string行;
 while((line = br.readLine())!= null){
    if(line.startsWith(“abc”)){
        // 做一点事
    }
 }

但如果文件的第一行是“abcd”,则不匹配。 通过debugging,我发现第一个字符是一个0(不可打印的字符),因此它不会匹配。 为什么? 我如何可靠地确定哪些行以“abc”开头?

编辑:也许我应该指出,我用记事本创build文件

Windows在UTF-8上有一些问题,因此它是UTF-8 BOM(字节顺序标记)的重要用户 。

如果我的猜测是正确的,那么前三个字节将是(十六进制):0xef,0xbb,0xbf。

例如,如果Excel创建带有BOM前缀的UTF-8 CSV文件,那么记事本也不会感到意外…

编辑:毫不奇怪,似乎是这样的情况:看到这里 。

从会话0升级程序

我的程序使用DXGI API与DXGI输出和适配器进行交互。

我正在使用大多数命令行工具开发它,因为我不需要任何GUI。

我也通过Bitvise SSH服务器访问我的PowerShell实例 – 只要我通过这个PowerShell实例运行我编译的program.exe,据我所知,这意味着我的程序运行在会话0,这意味着我只能访问DXGIfunction的一个子集(请参阅在会话0进程中使用Direct3D )。

有什么办法可以绕过这个要求吗? 有没有一个标志,我可以传递给program.exe,以某种方式popup它的会话0?

如果不是通过WinAPI,如果你可以使用和启动额外的exe来启动你的program.exe,我想你可以尝试使用psexec实用程序: http : //technet.microsoft.com/en-us/sysinternals/bb897553 。

我想也有类似的实用程序。

编辑:您也可以使用psexec在本地框上启动进程,请参阅参考“计算机”参数:

计算机直接运行PsExec在计算机或指定的计算机上运行应用程序。 如果省略计算机名称PsExec在本地系统上运行应用程序,并且输入计算机名称“\ *”,则PsExec在当前域中的所有计算机上运行应用程序。

另一个编辑我能够在我的会话中启动notepad.exe模拟你可能有什么:

psexec -i 0 psexec -s -i 1 C:\windows\system32\Notepad.exe 

此命令行开始使用psexec在会话0(在系统帐户下)启动自身,然后新的psexec调用notepad.exe在我的会话(会话1)中显示。 而且它确实有用。 当然,你需要管理员权限来运行这些命令。

批量获得0个字节文件的计数

我试图运行一个批处理来获得一个目录中的0字节文件的数量。 如果计数是一个或多个,那么我想删除文件,否则退出。 这是我迄今为止。

@echo off if "%~z1" == "" ( echo File does not exist. ) else if "%~z1" == "0" ( echo File is empty. ) else ( echo File is non-empty. ) 

(已编辑,请参阅评论,下面的原始答案)

以下脚本计算目录中的空文件,然后,如果计数结果大于0 ,则删除空文件。 该目录被指定为批处理脚本的参数。 例如,如果您需要处理C:\Users\DS\Downloads ,请像这样调用脚本(假设script.bat是脚本文件的名称):

 script.bat C:\Users\DS\Downloads 

这是脚本:

 @ECHO OFF IF "%~1" == "" (ECHO Usage: %~nx0 path\to\files& GOTO :EOF) SET workdir=%1 SET count=0 SET "command=SET /A count+=1" CALL :processempty ECHO Number of empty files: %count% IF %count% GTR 0 ( ECHO Deleting files... SET "command=DEL %%F" CALL :processempty ) GOTO :EOF :processempty FOR %%F IN ("%workdir%\*") DO ( IF "%%~zF" == "0" %command% ) 

原始答案如下:

 @ECHO OFF SETLOCAL SET firstfile= SET delfirstfile= FOR %%F IN (*) DO ( IF "%%~zF" == "0" ( IF DEFINED firstfile ( ECHO DEL "%%F" SET delfirstfile=1 ) ELSE ( SET "firstfile=%%F" ) ) ) IF DEFINED delfirstfile ECHO DEL "%firstfile%" ENDLOCAL 

上面的脚本是这样的:

  1. 它遍历当前目录中的所有文件并检查其大小。

  2. 当找到第一个空文件时,它的名字被存储到一个变量中。

  3. 每个后续的空文件被删除,另一个变量被设置为表明第一个空文件也应该被删除。

  4. 在循环之后,指示符变量被检查。 如果设置,则删除第一个空文件。

PS。 我会建议你首先运行这个脚本,以确保它能正常工作。 之后,您需要在两个DEL命令的前面删除ECHO ,让脚本实际删除文件。

如何查看指针映射中的指针是否为0

我做了一个地图,我需要在另一个线程的地图,所以我做了一个指向我的地图,并将其发送到另一个线程的指针。 但是,当我想看如果地图中的值不是NULL(指针),我得到一个错误。

这是一个示例代码:

#include <iostream> #include <vector> #include <map> using namespace std; int main() { int test = 1; map<int,void *> handle; map<int,void *> * handle2; handle[0] = &test; handle2 = &handle; if(*handle2[0]) { cout << "Works\n"; } system("Pause"); return false; } 

这是我得到的错误:

错误C2451:types'std :: map <_Kty,_Ty>'的条件expression式是非法的

在这种情况下,我怎样才能剔除0指针呢?

handle2是一个指向地图的指针,所以handle2[0] (相当于*handle2 )就是地图本身。 如错误所述,这不能用作条件表达式。

如果你想检查handle2是否为空,就说handle2 ; 对于键为0的地图元素,您需要(*handle2)[0]

 if(*handle2[0]) 

一种可能性:

 if((*handle2)[0]) 

另一个(对我来说有点神秘):

 if(handle2[0][0]) 

当后续列有图像时,列表控件将图像的空间添加到列0

我遇到了Windows列表控件的一个问题(我特别使用MFC,但它看起来像适用于Windows公共控件库中的所有列表控件)。

在我的具体情况,我想创build一个列表控件,有两列或更多列。 第一列(0)是纯文本的,用于允许用户通过input该行中的文本跳转到条目。 第二列(或三,四,或其他)有一个图像(或图像和文字,无论是哪种方式)。

这一切都很好,可以轻松完成,但是最后的列表控件最终会在第0列中的文本左侧留下一个空格(它可能在RTL系统的右侧)。 这个间隔似乎是保留一个图像,我不知道一个办法来防止它。 (排列列的具体顺序并没有改变任何东西。)

环顾四周,我发现一些其他人抱怨同样的事情,特别是这个线程导致这个线程 。 build议的解决scheme不起作用,因为如上所述,只是缩小列零的宽度只是切断了文本而不是图像间隔(加上,然后必须防止和/或处理用户试图对列宽进行的任何更改使)。

有没有人有任何想法,如何解决这个问题,从头开始编写一个列表控件或在CodeProject / CodeGuru /等使用一个太花哨的网格控件?

非常感谢。

你有没有尝试改变LVITEM结构的iIndent成员? MSDN说:

iIndent
版本4.70。 要缩进项目的图像宽度的数量。 单个缩进等于项目图像的宽度。 因此,值1将缩进一个图像的宽度,值2缩进两个图像,依此类推。 请注意,此字段仅支持项目。 尝试设置子项缩进将导致调用函数失败。

列0在ListView中是特殊的。 只要您将一个小图像列表分配给ListView,控件就希望您在第0列中显示一个图像,因此它留下空间。

解决方案:

  1. 使列0为零宽度,给它你想让用户能够键入的值。 列1成为您的“第一个”文本列。 列2+是为您的图像。 你需要全行选择样式才能工作。 是的,你必须防止用户调整第0列。是的,这是一个痛苦。
  2. 使列有一个图像是0列,并使用LVM_SETCOLUMNORDERARRAY重新排列显示顺序
  3. 所有者绘制项目。
  4. 给列0一个图标(只是为了涵盖所有的基地)

将0个字符写入文件描述符

我有一个特定的硬件驱动程序,要求我在其文件描述符上调用_write(fd, 0, 0)以触​​发某些特定的行为。

我希望能够从Python做到这一点 – 请任何人都可以提出一种方法来实现这一点?


编辑(应该把这个在开始,对不起!):

事情已经被尝试,不工作:

 f.write("") os.write(fd, "") os.fdsync(fd) 

如果你真的需要一个空指针(一个可怕的驱动程序设计 – 一个ioctl会好得多),你将不得不通过ctypes

至少,

 import ctypes ctypes.cdll.msvcrt._write(1, 0, 0) 

似乎工作。

作为一个函数的os模块称为write

 import os os.write(fd, b"") 

试图确定打印机状态总是返回0离线和在线打印机

我的目标是确定打印机的当前状态。 我find了下面的代码 。 这是一个稍微修改的版本来修复内存泄漏和错误:

#include <Winspool.h> int GetPrinterStatus( char* szPrnName ) { HANDLE hHandle = 0; // Handle of the printer DWORD dwStatus = 0; // Printer status we should receive DWORD dwSize = 0; // Size of memory we should // allocate for PRINTER_INFO_2 PRINTER_INFO_2* pPrnInfo2 = 0; // Structure specifies detailed // printer information DEVMODE DevMode = {0}; // Structure contains information // about the device initialization // and environment of a printer PRINTER_DEFAULTS PrnDef = { 0, &DevMode, PRINTER_ACCESS_USE }; // Open printer with name szPrnName if( !OpenPrinter( szPrnName, &hHandle, &PrnDef ) ) return -1; // Error // How many memory should be allocated for printer data? GetPrinter( hHandle, 2, 0, 0, &dwSize ); if( !dwSize ) { ClosePrinter( hHandle ); return -1; // Error } // Allocate memory pPrnInfo2 = (PRINTER_INFO_2*)malloc( dwSize ); // Receive printer details if(!GetPrinter( hHandle, 2, (LPBYTE)pPrnInfo2, dwSize, &dwSize )) { ClosePrinter( hHandle ); free( pPrnInfo2 ); return -1; // Error } dwStatus = pPrnInfo2->Status; // Free allocated memory free( pPrnInfo2 ); // Close printer ClosePrinter( hHandle ); return dwStatus; } 

所以,当我为这台打印机运行它时,它是offline

在这里输入图像说明

喜欢这个:

 int status = GetPrinterStatus("POS58"); 

我收到的状态是0 ,这与我为一个function打印机调用它完全一样

然后我尝试用OpenPrinterreplaceOpenPrinter调用,并使用PRINTER_OPTION_NO_CACHE选项,但它没有帮助。

我究竟做错了什么?

这个离线状态(是的,有多个)不是实际存储为状态位,而是作为pPrnInfo2-> Attributes中的PRINTER_ATTRIBUTE_WORK_OFFLINE位。 看到这个知识库文章 。

它由USB端口监视器(USBMON)为USB打印机设置,但也可以通过“使用打印机离线”菜单选项在“查看打印内容”窗口中由用户打开或关闭:

在这里输入图像说明

仅供参考,这里是该属性在Windows 10中各个地方显示的状态字符串:

  • 在打印管理(也是您的打印窗口) – “离线”
  • 设备和打印机详细信息视图状态 – “”(空字符串)
  • “设备和打印机”中的“查看打印内容”窗口 – “脱机使用打印机”

其他离线状态标志的位置是:

  • PRINTER_STATUS_OFFLINE – 您在打印机信息状态下所期待的
  • JOB_STATUS_OFFLINE – 在作业状态(通常是当前的打印作业)

请注意,每台打印机的确切状态行为取决于驱动程序,因为驱动程序可以设置任何喜欢的状态。 例如,我不记得看到网络打印机使用PRINTER_ATTRIBUTE_WORK_OFFLINE,但我最近看到一个Epson收据打印机使用PRINTER_STATUS_NOT_AVAILABLE。

窗口铬刷新标签0(或当前标签)通过命令行

我试图用pythonwebbrowser模块来做到这一点。 但它不具有Chromium特定function。 有另一种方法吗? 可能与批处理脚本?

我自己使用这个(我写的很快,因为它只是个人使用)。 有了很多清理,你可能会得到你想要的。 请参阅https://developers.google.com/chrome-developer-tools/docs/remote-debugging

 import urllib2 import urllib import os import subprocess import json from websocket import create_connection def refresh_page(url): data = json.load(urllib2.urlopen('http://localhost:9222/json')) found_page = False for page in data: if page['url'].lower() == url.lower(): found_page = True websocketURL = page['webSocketDebuggerUrl'] ws = create_connection(websocketURL) obj = { "id": 0, "method": "Page.reload", "params": { "ignoreCache": True, "scriptToEvaluateOnLoad": "" } } dev_request = json.dumps(obj) ws.send(dev_request) result = ws.recv() ws.close() if not found_page: raise Exception("No pageFound") def open_or_refresh(file_name): file_name = "".join ( [f if f in r'\/:*?"<>|' else urllib.quote(f) for f in file_name] ) file_name = 'file:///' + file_name.replace('\\', '/') file_name = file_name.encode('ascii', 'ignore') try: refresh_page(file_name) except: cmd = (r'"%(LOCALAPPDATA)s\Google\Chrome\Application\chrome.exe"'%os.environ + r' --remote-debugging-port=9222 "%s"' % file_name) subprocess.Popen(cmd) open_or_refresh(r"C:\test.html") open_or_refresh(r"C:\test.html") 

如何从失败的命令返回退出码0

我想从失败的命令返回退出代码“0”。 有没有更简单的方法来做到这一点,而不是:

function a() { ls aaaaa 2>&1; } if ! $(a); then return 0 else return 5 fi 

只需附加return 0到函数强制一个函数总是退出成功。

 function a() { ls aaaaa 2>&1 return 0 } a echo $? # prints 0 

如果你想以任何理由进行内联,你可以追加|| true || true的命令:

 ls aaaaa 2>&1 || true echo $? # prints 0 

如果你想反转退出状态,简单的把命令加上!

 ! ls aaaaa 2>&1 echo $? # prints 0 ! ls /etc/resolv.conf 2>&1 echo $? # prints 1 

另外,如果你陈述你正在努力达到的总体,我们可能能够引导你更好的答案。

从用户空间读取内核驱动程序,但写回始终为0

所以我正在努力通过内核驱动程序编程,目前我正试图在应用程序和内核驱动程序之间build立一个简单的数据传输。

我正在使用简单的字符设备作为这两者之间的一个链接,并且我已经成功地将数据传输到了驱动程序,但是我无法获得有意义的数据回到用户空间。

内核驱动程序如下所示:

#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> /* printk() */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/proc_fs.h> #include <asm/uaccess.h> /* copy_from/to_user */ MODULE_LICENSE("GPL"); //Declarations int memory_open(struct inode *inode, struct file *filp); int memory_release(struct inode *inode, struct file *filp); ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos); ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos); void memory_exit(void); int memory_init(void); /* Structure that declares the usual file access functions */ struct file_operations memory_fops = { read: memory_read, write: memory_write, open: memory_open, release: memory_release }; //Default functions module_init(memory_init); module_exit(memory_exit); /* Global variables of the driver */ /* Major number */ int memory_major = 60; /* Buffer to store data */ char* tx_buffer; char* rx_buffer; int BUFFER_SIZE=64; int actual_rx_size=0; int memory_init(void) { int result; /* Registering device */ result = register_chrdev(memory_major, "move_data", &memory_fops); if (result < 0) { printk( "<1>move_data: cannot obtain major number %d\n", memory_major); return result; } /* Allocating memory for the buffers */ //Allocate buffers tx_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); rx_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); //Check allocation was ok if (!tx_buffer || !rx_buffer) { result = -ENOMEM; goto fail; } //Reset the buffers memset(tx_buffer,0, BUFFER_SIZE); memset(rx_buffer,0, BUFFER_SIZE); printk("<1>Inserting memory module\n"); return 0; fail: memory_exit(); return result; } void memory_exit(void) { /* Freeing the major number */ unregister_chrdev(memory_major, "memory"); /* Freeing buffers */ if (tx_buffer) { kfree(tx_buffer); //Note kfree } if (rx_buffer) { kfree(rx_buffer); //Note kfree } printk("<1>Removing memory module\n"); } //Read function ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { printk("user requesting data, our buffer has (%d) \n", actual_rx_size); /* Transfering data to user space */ int retval = copy_to_user(buf,rx_buffer,actual_rx_size); printk("copy_to_user returned (%d)", retval); return retval; } ssize_t memory_write( struct file *filp, char *buf, size_t count, loff_t *f_pos) { //zero the input buffer memset(tx_buffer,0,BUFFER_SIZE); memset(rx_buffer,0,BUFFER_SIZE); printk("New message from userspace - count:%d\n",count); int retval = copy_from_user(tx_buffer,buf,count); printk("copy_from_user returned (%d) we read [%s]\n",retval , tx_buffer); printk("initialize rx buffer..\n"); memcpy(rx_buffer,tx_buffer, count); printk("content of rx buffer [%s]\n", rx_buffer); actual_rx_size = count; return count; //inform that we read all (fixme?) } //Always successfull int memory_open(struct inode *inode, struct file *filp) { return 0; } int memory_release(struct inode *inode, struct file *filp) { return 0; } 

用户空间应用程序也很简单:

 #include <unistd.h> //open, close | always first, defines compliance #include <fcntl.h> //O_RDONLY #include <stdio.h> #include <stdlib.h> //printf #include <string.h> int main(int args, char *argv[]) { int BUFFER_SIZE = 20; char internal_buf[BUFFER_SIZE]; int to_read = 0; memset(internal_buf,0,BUFFER_SIZE); if (args < 3) { printf("2 Input arguments needed\nTo read 10 bytes: \"%s read 10\" \ \nTo write string \"hello\": \"%s write hello\"\nExiting..\n", argv[0], argv[0]); return 1; } //Check the operation if (strcmp(argv[1],"write") == 0) { printf("input lenght:%d", strlen(argv[2])); //Make sure our write fits to the internal buffer if(strlen(argv[2]) >= BUFFER_SIZE) { printf("too long input string, max buffer[%d]\nExiting..", BUFFER_SIZE); return 2; } printf("write op\n"); memcpy(internal_buf,argv[2], strlen(argv[2])); printf("Writing [%s]\n", internal_buf); FILE * filepointer; filepointer = fopen("/dev/move_data", "w"); fwrite(internal_buf, sizeof(char) , strlen(argv[2]), filepointer); fclose(filepointer); } else if (strcmp(argv[1],"read") == 0) { printf("read op\n"); to_read = atoi(argv[2]); FILE * filepointer; filepointer = fopen("/dev/move_data", "r"); int retval = fread(internal_buf, sizeof(char) , to_read, filepointer); fclose(filepointer); printf("Read %d bytes from driver string[%s]\n", retval, internal_buf); } else { printf("first argument has to be 'read' or 'write'\nExiting..\n"); return 1; } return 0; } 

当我执行我的应用程序时,会发生什么情况:

 ./rw write "testing testing" kernel side: [ 2696.607586] New message from userspace - count:15 [ 2696.607591] copy_from_user returned (0) we read [testing testing] [ 2696.607593] initialize rx buffer.. [ 2696.607594] content of rx buffer [testing testing] 

所以看起来都是正确的 但是当我尝试阅读:

 ./rw read 15 read op Read 0 bytes from driver string[] Kernel [ 617.096521] user requesting data, our buffer has (15) [ 575.797668] copy_to_user returned (0) [ 617.096528] copy_to_user returned (0) 

我想这很简单,我做错了,因为如果我不返回0,我可以得到一些数据,但是例如,如果我用猫读,它将继续循环不休。

我想明白我在思考中犯了什么错误。 有没有一种方法,内核驱动程序只是吐出它的缓冲区,然后返回0,这样我就不必在那里build立一些协议,以照顾有多less数据已被读取等等。

感谢您的build议!

编辑:更正memory_write函数中的printk语句,并添加memory_read函数跟踪

你的读取函数总是返回0,因为你正在返回retval ,而不是读取的字节数。 只要copy_to_user()调用总是成功, retval将始终为0.相反,只要copy_to_user()成功,您应该返回实际写入用户空间的字节数。 本文档指出copy_to_user()返回无法复制的总字节数。

顺便说一句,你忽略了伯爵的价值。 用户所请求的数据很可能比缓冲区中的数据少。 你不应该忽视伯爵。

现在,您的函数永远不会返回0,因此返回0非常重要,因为它告诉用户应用程序没有更多数据可供读取,用户应用程序应该关闭设备文件。

您需要跟踪您的驱动程序已经读取了多少个字节与已经写入了多少个字节。 这可以用你的actual_rx_size来实现。

尝试这个:

 //Read function ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { ssize_t bytes; if (actual_rx_size < count) bytes = actual_rx_size; else bytes = count; printk("user requesting data, our buffer has (%d) \n", actual_rx_size); /* Check to see if there is data to transfer */ if (bytes == 0) return 0; /* Transfering data to user space */ int retval = copy_to_user(buf,rx_buffer,bytes); if (retval) { printk("copy_to_user() could not copy %d bytes.\n", retval); return -EFAULT; } else { printk("copy_to_user() succeeded!\n"); actual_rx_size -= bytes; return bytes; } }