Commit b5da5edb authored by Zhangyi Chen's avatar Zhangyi Chen

Merge branch 'master' of github.com:brpc/brpc

parents d76cc734 fdea93a0
......@@ -9,9 +9,14 @@
*.pb.cc
*.pb.h
*.prof
*.so
/output
/test/output
#ignore hidden files
.*
*.swp
#ignore auto-generated files
config.mk
src/butil/config.h
......@@ -34,33 +34,16 @@ BUTIL_SOURCES = \
src/butil/third_party/nspr/prtime.cc \
src/butil/third_party/symbolize/demangle.cc \
src/butil/third_party/symbolize/symbolize.cc \
src/butil/third_party/xdg_mime/xdgmime.c \
src/butil/third_party/xdg_mime/xdgmimealias.c \
src/butil/third_party/xdg_mime/xdgmimecache.c \
src/butil/third_party/xdg_mime/xdgmimeglob.c \
src/butil/third_party/xdg_mime/xdgmimeicon.c \
src/butil/third_party/xdg_mime/xdgmimeint.c \
src/butil/third_party/xdg_mime/xdgmimemagic.c \
src/butil/third_party/xdg_mime/xdgmimeparent.c \
src/butil/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc \
src/butil/third_party/snappy/snappy-sinksource.cc \
src/butil/third_party/snappy/snappy-stubs-internal.cc \
src/butil/third_party/snappy/snappy.cc \
src/butil/third_party/murmurhash3/murmurhash3.cpp \
src/butil/allocator/type_profiler_control.cc \
src/butil/arena.cpp \
src/butil/at_exit.cc \
src/butil/atomicops_internals_x86_gcc.cc \
src/butil/barrier_closure.cc \
src/butil/base_paths.cc \
src/butil/base_paths_posix.cc \
src/butil/base64.cc \
src/butil/base_switches.cc \
src/butil/big_endian.cc \
src/butil/bind_helpers.cc \
src/butil/callback_helpers.cc \
src/butil/callback_internal.cc \
src/butil/command_line.cc \
src/butil/cpu.cc \
src/butil/debug/alias.cc \
src/butil/debug/asan_invalid_access.cc \
......@@ -94,29 +77,10 @@ BUTIL_SOURCES = \
src/butil/memory/aligned_memory.cc \
src/butil/memory/ref_counted.cc \
src/butil/memory/ref_counted_memory.cc \
src/butil/memory/shared_memory_posix.cc \
src/butil/memory/singleton.cc \
src/butil/memory/weak_ptr.cc \
src/butil/nix/mime_util_xdg.cc \
src/butil/nix/xdg_util.cc \
src/butil/path_service.cc \
src/butil/posix/file_descriptor_shuffle.cc \
src/butil/posix/global_descriptors.cc \
src/butil/process/internal_linux.cc \
src/butil/process/kill.cc \
src/butil/process/kill_posix.cc \
src/butil/process/launch.cc \
src/butil/process/launch_posix.cc \
src/butil/process/process_handle_linux.cc \
src/butil/process/process_handle_posix.cc \
src/butil/process/process_info_linux.cc \
src/butil/process/process_iterator.cc \
src/butil/process/process_iterator_linux.cc \
src/butil/process/process_linux.cc \
src/butil/process/process_metrics.cc \
src/butil/process/process_metrics_linux.cc \
src/butil/process/process_metrics_posix.cc \
src/butil/process/process_posix.cc \
src/butil/rand_util.cc \
src/butil/rand_util_posix.cc \
src/butil/fast_rand.cpp \
......@@ -139,9 +103,6 @@ BUTIL_SOURCES = \
src/butil/synchronization/cancellation_flag.cc \
src/butil/synchronization/condition_variable_posix.cc \
src/butil/synchronization/waitable_event_posix.cc \
src/butil/sys_info.cc \
src/butil/sys_info_linux.cc \
src/butil/sys_info_posix.cc \
src/butil/threading/non_thread_safe_impl.cc \
src/butil/threading/platform_thread_linux.cc \
src/butil/threading/platform_thread_posix.cc \
......
......@@ -16,27 +16,27 @@ NOTE: following tests were done in 2015, which may not reflect latest status of
## UB
com组(INF前身)在08年开发的RPC框架,在百度产品线广泛使用,已被brpc代替。UB的每个请求独占一个连接(连接池),在大规模服务中每台机器都需要保持大量的连接,限制了其使用场景,像百度的分布式系统都不用UB。UB只支持nshead+mcpack协议,也没怎么考虑扩展性,所以增加新协议和新功能往往要调整大段代码,在实践中大部分人“知难而退”了。UB缺乏调试和运维接口,服务的运行状态对用户基本是黑盒,只能靠低效地打日志来追踪问题,服务出现问题时常要拉上维护者一起排查,效率很低。UB有多个变种:
百度在08年开发的RPC框架,在百度产品线广泛使用,已被brpc代替。UB的每个请求独占一个连接(连接池),在大规模服务中每台机器都需要保持大量的连接,限制了其使用场景,像百度的分布式系统没有用UB。UB只支持nshead+mcpack协议,也没怎么考虑扩展性,所以增加新协议和新功能往往要调整大段代码,在实践中大部分人“知难而退”了。UB缺乏调试和运维接口,服务的运行状态对用户基本是黑盒,只能靠低效地打日志来追踪问题,服务出现问题时常要拉上维护者一起排查,效率很低。UB有多个变种:
* ubrpc:INF在10年基于UB开发的RPC框架,用.idl文件(类似.proto)描述数据的schema,而不是手动打包。这个RPC有被使用,但不广泛。
* ubrpc:百度在10年基于UB开发的RPC框架,用.idl文件(类似.proto)描述数据的schema,而不是手动打包。这个RPC有被使用,但不广泛。
- nova_pbrpc:网盟在12年基于UB开发的RPC框架,用protobuf代替mcpack作为序列化方法,协议是nshead + user's protobuf。
- public_pbrpc:INF在13年初基于UB开发的RPC框架,用protobuf代替mcpack作为序列化方法,但协议与nova_pbrpc不同,大致是nshead + meta protobuf。meta protobuf中有个string字段包含user's protobuf。由于用户数据要序列化两次,这个RPC的性能很差,没有被推广开来。
- nova_pbrpc:百度网盟团队在12年基于UB开发的RPC框架,用protobuf代替mcpack作为序列化方法,协议是nshead + user's protobuf。
- public_pbrpc:百度在13年初基于UB开发的RPC框架,用protobuf代替mcpack作为序列化方法,但协议与nova_pbrpc不同,大致是nshead + meta protobuf。meta protobuf中有个string字段包含user's protobuf。由于用户数据要序列化两次,这个RPC的性能很差,没有被推广开来。
我们以在网盟广泛使用的nova_pbrpc为UB的代表。测试时其代码为r10500。早期的UB支持CPOOL和XPOOL,分别使用[select](http://linux.die.net/man/2/select)[leader-follower模型](http://kircher-schwanninger.de/michael/publications/lf.pdf),后来提供了EPOOL,使用[epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)处理多路连接。鉴于产品线大都是用EPOOL模型,我们的UB配置也使用EPOOL。UB只支持[连接池](client.md#连接方式),结果用“**ubrpc_mc**"指代(mc代表"multiple
我们以在百度网盟团队广泛使用的nova_pbrpc为UB的代表。测试时其代码为r10500。早期的UB支持CPOOL和XPOOL,分别使用[select](http://linux.die.net/man/2/select)[leader-follower模型](http://kircher-schwanninger.de/michael/publications/lf.pdf),后来提供了EPOOL,使用[epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)处理多路连接。鉴于产品线大都是用EPOOL模型,我们的UB配置也使用EPOOL。UB只支持[连接池](client.md#连接方式),结果用“**ubrpc_mc**"指代(mc代表"multiple
connection")。虽然这个名称不太准确(见上文对ubrpc的介绍),但在本文的语境下,请默认ubrpc = UB。
## hulu-pbrpc
INF在13年基于saber(kylin变种)和protobuf实现的RPC框架,hulu在实现上有较多问题:未封装的引用计数,混乱的生命周期,充斥的race conditions和ABA problems,运行质量不可靠,比如短链接从来没有能正常运行过。之后迅速被brpc代替,测试时其代码为`pbrpc_2-0-15-27959_PD_BL`。hulu-pbrpc只支持单连接,结果用“**hulu-pbrpc**"指代。
百度在13年基于saber(kylin变种)和protobuf实现的RPC框架,hulu在多线程实现上有较多问题,已被brpc代替,测试时其代码为`pbrpc_2-0-15-27959_PD_BL`。hulu-pbrpc只支持单连接,结果用“**hulu-pbrpc**"指代。
## brpc
INF在2014年底开发至今的rpc产品,支持百度内所有协议(不限于protobuf),并第一次统一了百度内主要分布式系统的RPC框架。测试时代码为r31906(开发请使用@ci-base保持更新)。brpc既支持单连接也支持连接池,前者的结果用"**baidu-rpc**"指代,后者用“**baidu-rpc_mc**"指代。
INF在2014年底开发至今的rpc产品,支持百度内所有协议(不限于protobuf),并第一次统一了百度主要分布式系统和业务线的RPC框架。测试时代码为r31906。brpc既支持单连接也支持连接池,前者的结果用"**baidu-rpc**"指代,后者用“**baidu-rpc_mc**"指代。
## sofa-pbrpc
大搜在13年基于boost::asio和protobuf实现的RPC框架,有多个版本,咨询相关同学后,确认ps/opensource下的和github上的较新,且会定期同步。故测试使用使用ps/opensource下的版本。测试时其代码为`sofa-pbrpc_1-0-2_BRANCH`。sofa-pbrpc只支持单连接,结果用“**sofa-pbrpc**”指代。
百度大搜团队在13年基于boost::asio和protobuf实现的RPC框架,有多个版本,咨询相关同学后,确认ps/opensource下的和github上的较新,且会定期同步。故测试使用使用ps/opensource下的版本。测试时其代码为`sofa-pbrpc_1-0-2_BRANCH`。sofa-pbrpc只支持单连接,结果用“**sofa-pbrpc**”指代。
## apache thrift
......
This diff is collapsed.
......@@ -132,7 +132,7 @@ os.move_to(cntl->request_attachment());
Notes on http header:
- 根据 HTTP 协议[规定](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), header 的 field_name部分不区分大小写。在r33861前,field_name都转为了小写,在r33861后,大小写能保持不变(仍然支持大小写不敏感)
- 根据 HTTP 协议[规定](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), header 的 field_name部分不区分大小写。brpc对于field_name大小写保持不变,且仍然支持大小写不敏感
- 如果 HTTP 头中出现了相同的 field_name, 根据协议[规定](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),value将被合并到一起, 中间用逗号(,) 分隔, 具体value如何理解,需要用户自己确定.
- query之间用"&"分隔, key和value之间用"="分隔, value可以省略,比如key1=value1&key2&key3=value3中key2是合理的query,值为空字符串。
......@@ -144,12 +144,11 @@ Notes on http header:
当Server返回的http status code不是2xx时,该次http访问即视为失败,client端会设置对应的ErrorCode:
- 在r31923前,1xx和3xx错误对应EPROTONOSUPPORT,4xx错误对应EREQUEST,其余错误对应EINTERNAL。http body不会置入`cntl->response_attachment()`
- 在r31923后,所有错误被统一为EHTTP。如果用户发现`cntl->ErrorCode()`为EHTTP,那么可以检查`cntl->http_response().status_code()`以获得具体的http错误。同时http body会置入`cntl->response_attachment()`,用户可以把代表错误的html或json传递回来。
- 所有错误被统一为EHTTP。如果用户发现`cntl->ErrorCode()`为EHTTP,那么可以检查`cntl->http_response().status_code()`以获得具体的http错误。同时http body会置入`cntl->response_attachment()`,用户可以把代表错误的html或json传递回来。
# 压缩request body
在r33877后,调用Controller::set_request_compress_type(brpc::COMPRESS_TYPE_GZIP)可将http body用gzip压缩,并设置"Content-Encoding"为"gzip"。
调用Controller::set_request_compress_type(brpc::COMPRESS_TYPE_GZIP)可将http body用gzip压缩,并设置"Content-Encoding"为"gzip"。
# 解压response body
......@@ -172,9 +171,9 @@ if (encoding != NULL && *encoding == "gzip") {
# 持续下载
r33796前brpc client在下载一个超长的body时,需要一直等待直到body完整才会视作RPC结束,这个过程中超长body都会存在内存中,如果body是无限长的(比如直播用的flv文件),那么内存会持续增长,直到超时。换句话说,r33796前的brpc client不适合下载大文件。
通常下载一个超长的body时,需要一直等待直到body完整才会视作RPC结束,这个过程中超长body都会存在内存中,如果body是无限长的(比如直播用的flv文件),那么内存会持续增长,直到超时。这样的http client不适合下载大文件。
r33796后brpc client支持在读取完body前就结束RPC,让用户在RPC结束后再读取持续增长的body。注意这个功能不等同于“支持http chunked mode”,brpc的http实现一直支持解析chunked mode,这里的问题是如何让用户处理超长或无限长的body,和body是否以chunked mode传输无关。
brpc client支持在读取完body前就结束RPC,让用户在RPC结束后再读取持续增长的body。注意这个功能不等同于“支持http chunked mode”,brpc的http实现一直支持解析chunked mode,这里的问题是如何让用户处理超长或无限长的body,和body是否以chunked mode传输无关。
使用方法如下:
......@@ -215,4 +214,4 @@ r33796后brpc client支持在读取完body前就结束RPC,让用户在RPC结
# 访问带认证的Server
根据Server的认证方式生成对应的auth_data,并设置为http header "Authorization"的值。比如用的是curl,那就加上选项`-H "Authorization : <auth_data>"。`查询[giano文档](http://doc.noah.baidu.com/new/baas/base_tool.md)了解如何在Shell中生成auth_data。
根据Server的认证方式生成对应的auth_data,并设置为http header "Authorization"的值。比如用的是curl,那就加上选项`-H "Authorization : <auth_data>"。`
......@@ -2,7 +2,7 @@
brpc server在同端口支持所有的协议,大部分时候这对部署和运维更加方便。由于不同协议的格式大相径庭,严格地来说,同端口很难无二义地支持所有协议。出于解耦和可扩展性的考虑,也不太可能集中式地构建一个针对所有协议的分类器。我们的做法就是把协议归三类后逐个尝试:
- 第一类协议:标记或特殊字符在最前面,比如[baidu_std](baidu_std.md),hulu_pbrpc的前4个字符分别分别是PRPC和HULU,解析代码只需要检查前4个字节就可以知道协议是否匹配,最先尝试这类协议。这些协议在同一个连接上也可以共存。
- 第一类协议:标记或特殊字符在最前面,比如[baidu_std](baidu_std.md),hulu_pbrpc的前4个字符分别是PRPC和HULU,解析代码只需要检查前4个字节就可以知道协议是否匹配,最先尝试这类协议。这些协议在同一个连接上也可以共存。
- 第二类协议:有较为复杂的语法,没有固定的协议标记或特殊字符,可能在解析一段输入后才能判断是否匹配,目前此类协议只有http。
- 第三类协议:协议标记或特殊字符在中间,比如nshead的magic_num在第25-28字节。由于之前的字段均为二进制,难以判断正确性,在没有读取完28字节前,我们无法判定消息是不是nshead格式的,所以处理起来很麻烦,若其解析排在http之前,那么<=28字节的http消息便可能无法被解析,因为程序以为是“还未完整的nshead消息”。
......@@ -52,7 +52,7 @@ enum ProtocolType {
```
## 实现回调
均定义在struct Protocol中,该结构定义在[protocol.h](https://github.com/brpc/brpc/blob/master/src/brpc/protocol.h)。其中的parse必须实现,除此之外server端至少要实现process_request,client端至少要实现serialize_request,pack_request,process_response;
均定义在struct Protocol中,该结构定义在[protocol.h](https://github.com/brpc/brpc/blob/master/src/brpc/protocol.h)。其中的parse必须实现,除此之外server端至少要实现process_request,client端至少要实现serialize_request,pack_request,process_response
实现协议回调还是比较困难的,这块的代码不会像供普通用户使用的那样,有较好的提示和保护,你得先靠自己搞清楚其他协议中的类似代码,然后再动手,最后发给我们做code review。
......
......@@ -16,52 +16,12 @@ PLOG(FATAL) << "Fail to call function setting errno";
VLOG(1) << "verbose log tier 1";
CHECK_GT(1, 2) << "1 can't be greater than 2";
// public/common >= r32401支持限制打印频率。
LOG_EVERY_SECOND(INFO) << "High-frequent logs";
LOG_EVERY_N(ERROR, 10) << "High-frequent logs";
LOG_FIRST_N(INFO, 20) << "Logs that prints for at most 20 times";
LOG_ONCE(WARNING) << "Logs that only prints once";
```
## 配置comlog
```c++
// logging默认重定向至comlog,要配置comlog的话,要额外include comlog_sink.h
#include <butil/comlog_sink.h>
// 从./conf/log.conf读取comlog的配置。SetupFromConfig是我们提供的封装函数,不用像com_loadlog那样区分path和file。
if (logging::ComlogSink::GetInstance()->SetupFromConfig("conf/log.conf") != 0) {
LOG(ERROR) << "Fail to setup comlog from conf/log.conf";
return -1;
}
OR
// 直接调用com_loadlog从./conf/log.conf读取comlog的配置。
if (com_loadlog("./conf", "log.conf") != 0) {
LOG(ERROR) << "Fail to com_loadlog";
return -1;
}
OR
// 把日志打入./my_log/<process-name>.log中,comlog选项取默认值。
logging::ComlogSinkOptions options;
options.log_dir = "my_log";
if (logging::ComlogSink::GetInstance()->Setup(&options) != 0) {
LOG(ERROR) << "Fail to setup comlog from options";
return -1;
}
OR
// 把日志打入./log/<process-name>.log中,comlog选项取默认值。
if (logging::ComlogSink::GetInstance()->Setup(NULL) != 0) {
LOG(ERROR) << "Fail to setup comlog by default options";
return -1;
}
```
# DESCRIPTION
流式日志是打印复杂对象或模板对象的不二之选。大部分业务对象都很复杂,如果用printf形式的函数打印,你需要先把对象转成string,才能以%s输出。但string组合起来既不方便(比如没法append数字),还得分配大量的临时内存(string导致的)。C++中解决这个问题的方法便是“把日志流式地送入std::ostream对象”。比如为了打印对象A,那么我们得实现如下的函数:
......@@ -122,17 +82,17 @@ LOG(WARNING) << "Unusual thing happened ..." << ...;
LOG(TRACE) << "Something just took place..." << ...;
```
streaming log的日志等级是comlog和glog的合集,具体的来说,下表是日志等级的映射关系
streaming log的日志等级与glog映射关系如下
| streaming log | comlog | glog | 使用场景 |
| ------------- | ---------------------------- | -------------------- | ---------------------------------------- |
| FATAL | COMLOG_FATAL | FATAL (coredump) | 致命错误。但由于百度内大部分FATAL实际上非致命,所以streaming log的FATAL默认不像glog那样直接coredump,除非打开了[-crash_on_fatal_log](http://brpc.baidu.com:8765/flags/crash_on_fatal_log) |
| ERROR | COMLOG_FATAL | ERROR | 不致命的错误。 |
| WARNING | COMLOG_WARNING | WARNING | 不常见的分支。 |
| NOTICE | COMLOG_NOTICE | - | 一般来说你不应该使用NOTICE,它用于打印重要的业务日志,若要使用务必和检索端同学确认。glog没有NOTICE。 |
| INFO, TRACE | COMLOG_TRACE | INFO | 打印重要的副作用。比如打开关闭了某某资源之类的。 |
| VLOG(n) | COMLOG_TRACE | INFO | 打印分层的详细日志。 |
| DEBUG | COMLOG_TRACEVLOG(1) (NDEBUG) | INFOVLOG(1) (NDEBUG) | 仅为代码兼容性,基本没有用。若要使日志仅在未定义NDEBUG时才打印,用DLOG/DPLOG/DVLOG等即可。 |
| streaming log | glog | 使用场景 |
| ------------- | -------------------- | ---------------------------------------- |
| FATAL | FATAL (coredump) | 致命错误。但由于百度内大部分FATAL实际上非致命,所以streaming log的FATAL默认不像glog那样直接coredump,除非打开了[-crash_on_fatal_log](http://brpc.baidu.com:8765/flags/crash_on_fatal_log) |
| ERROR | ERROR | 不致命的错误。 |
| WARNING | WARNING | 不常见的分支。 |
| NOTICE | - | 一般来说你不应该使用NOTICE,它用于打印重要的业务日志,若要使用务必和检索端同学确认。glog没有NOTICE。 |
| INFO, TRACE | INFO | 打印重要的副作用。比如打开关闭了某某资源之类的。 |
| VLOG(n) | INFO | 打印分层的详细日志。 |
| DEBUG | INFOVLOG(1) (NDEBUG) | 仅为代码兼容性,基本没有用。若要使日志仅在未定义NDEBUG时才打印,用DLOG/DPLOG/DVLOG等即可。 |
## PLOG
......@@ -148,7 +108,7 @@ if (fd < 0) {
## noflush
如果你暂时不希望刷入comlog,加上noflush。这一般会用在打印循环中:
如果你暂时不希望刷到屏幕,加上noflush。这一般会用在打印循环中:
```c++
LOG(TRACE) << "Items:" << noflush;
......@@ -158,7 +118,7 @@ for (iterator it = items.begin(); it != items.end(); ++it) {
LOG(TRACE);
```
前两次TRACE日志都没有刷到comlog,而是还记录在thread-local缓冲中,第三次TRACE日志则把缓冲都刷入了comlog。如果items里面有三个元素,不加noflush的打印结果可能是这样的:
前两次TRACE日志都没有刷到屏幕,而是还记录在thread-local缓冲中,第三次TRACE日志则把缓冲都刷入了屏幕。如果items里面有三个元素,不加noflush的打印结果可能是这样的:
```
TRACE: ... Items:
......@@ -173,7 +133,7 @@ TRACE: ... item3
TRACE: ... Items: item1 item2 item3
```
r34694前noflush和调用处的pthread绑定,如果在noflush后发送了RPC(可能跨越pthread),那么日志输出可能不符合预期。r34694后noflush支持bthread,可以实现类似于UB的pushnotice的效果,即检索线程一路打印都暂不刷出(加上noflush),直到最后检索结束时再一次性刷出。注意,如果检索过程是异步的,就不应该使用noflush,因为异步显然会跨越bthread,使noflush仍然失效。
noflush支持bthread,可以实现类似于UB的pushnotice的效果,即检索线程一路打印都暂不刷出(加上noflush),直到最后检索结束时再一次性刷出。注意,如果检索过程是异步的,就不应该使用noflush,因为异步显然会跨越bthread,使noflush仍然失效。
## LOG_IF
......@@ -299,7 +259,7 @@ CHECK(x > y); // Check failed: x > y.
## LogSink
streaming log通过logging::SetLogSink修改日志刷入的目标,默认是屏幕。用户可以继承LogSink,实现自己的日志打印逻辑。我们默认提供了个LogSink实现:
streaming log通过logging::SetLogSink修改日志刷入的目标,默认是屏幕。用户可以继承LogSink,实现自己的日志打印逻辑。我们默认提供了个LogSink实现:
### StringSink
......@@ -316,9 +276,3 @@ TEST_F(StreamingLogTest, log_at) {
::logging::SetLogSink(old_sink);
}
```
### ComlogSink
定义在butil/comlog_sink.h中,把日志打印入comlog,主要用于线上系统,用法见[SYNOPSIS](#SYNOPSIS)一段。
使用ComlogSink的streaming log可以和com_writelog, ul_writelog混用。你并不需要把程序中所有日志都换成streaming log。
This diff is collapsed.
This diff is collapsed.
brpc uses [butil::IOBuf](https://github.com/brpc/brpc/blob/master/src/butil/iobuf.h) as data structure for attachment storage and HTTP body. It is a non-contiguous zero copy buffer, which has been proved in other projects as excellent performance. The interface of `IOBuf` is similar to `std::string`, but not the same.
If you used the `BufHandle` in Kylin before, you should notice the difference in convenience of `IOBuf`: the former hardly had any encapsulation, leaving the internal structure directly in front of the user. The user must carefully handle the reference count, which is very error prone, leading to lots of bugs.
# What IOBuf can:
- Default constructor doesn't involve copying.
- Explicit copy doesn't change source IOBuf. Only copy the management structure of IOBuf instead of the data.
- Append another IOBuf without copy.
- Append string involves copy.
- Read from/Write into fd.
- Convert to protobuf and vice versa.
- IOBufBuilder可以把IOBuf当std::ostream用。
# What IOBuf can't:
- Used as general storage structure. IOBuf should not keep a long life cycle to prevent multiple memory blocks (8K each) being locked by one IOBuf object.
# Slice
Slice 16 bytes from IOBuf:
```c++
source_buf.cut(&heading_iobuf, 16); // cut all bytes of source_buf when its length < 16
```
Remove 16 bytes:
```c++
source_buf.pop_front(16); // Empty source_buf when its length < 16
```
# Concatenate
Append to another IOBuf:
```c++
buf.append(another_buf); // no data copy
```
Append std::string
```c++
buf.append(str); // copy data of str into buf
```
# Parse
Parse protobuf from IOBuf
```c++
IOBufAsZeroCopyInputStream wrapper(&iobuf);
pb_message.ParseFromZeroCopyStream(&wrapper);
```
Parse IOBuf as user-defined structure
```c++
IOBufAsZeroCopyInputStream wrapper(&iobuf);
CodedInputStream coded_stream(&wrapper);
coded_stream.ReadLittleEndian32(&value);
...
```
# Serialize
Serialize protobuf into IOBuf
```c++
IOBufAsZeroCopyOutputStream wrapper(&iobuf);
pb_message.SerializeToZeroCopyStream(&wrapper);
```
Append printable data into IOBuf
```c++
IOBufBuilder os;
os << "anything can be sent to std::ostream";
os.buf(); // IOBuf
```
# Print
```c++
std::cout << iobuf;
std::string str = iobuf.to_string();
```
# Performance
IOBuf has excellent performance in general aspects:
| Action | Throughput | QPS |
| ---------------------------------------- | ----------- | ------- |
| Read from file -> Slice 12+16 bytes -> Copy -> Merge into another buffer ->Write to /dev/null | 240.423MB/s | 8586535 |
| Read from file -> Slice 12+128 bytes -> Copy-> Merge into another buffer ->Write to /dev/null | 790.022MB/s | 5643014 |
| Read from file -> Slice 12+1024 bytes -> Copy-> Merge into another buffer ->Write to /dev/null | 1519.99MB/s | 1467171 |
\ No newline at end of file
# Multi-protocol support in the server side
brpc server supports all protocols in the same port, and it makes deployment and maintenance more convenient in most of the time. Since the format of different protocols is very different, it is hard to support all protocols in the same port unambiguously. In consider of decoupling and extensibility, it is also hard to build a multiplexer for all protocols. Thus our way is to classify all protocols into three categories and try one by one:
- First-class protocol: Special characters are marked in front of the protocol data, for example, the data of protocol [baidu_std](baidu_std.md) and hulu_pbrpc begins with 'PRPC' and 'HULU' respectively. Parser just check first four characters to know whether the protocol is matched. This class of protocol is checked first and all these protocols can share one TCP connection.
- Second-class protocol: Some complex protocols without special marked characters can only be detected after several input data are parsed. Currently only HTTP is classified into this category.
- Third-class protocol: Special characters are in the middle of the protocol data, such as the magic number of nshead protocol is the 25th-28th characters. It is complex to handle this case because without reading first 28 bytes, we cannot determine whether the protocol is nshead. If it is tried before http, http messages less than 28 bytes may not be parsed, since the parser consider it as an uncomplete nshead message.
Considering that there will be only one protocol in most connections, we record the result of last selection so that it will be tried first when further data comes. It reduces the overhead of matching protocols to nearly zero for long connections. Although the process of matching protocols will be run everytime for short connections, the bottleneck of short connections is not in here and this method is still fast enough. If there are lots of new protocols added into brpc in the future, we may consider some heuristic methods to match protocols.
# Multi-protocol support in the client side
Unlike the server side that protocols must be dynamically determined based on the data on the connection, the client side as the originator, naturally know their own protocol format. As long as the protocol data is sent through connection pool or short connection, which means it has exclusive usage of that connection, then the protocol can have any complex (or bad) format. Since the client will record the protocol when sending the data, it will use that recored protocol to parse the data without any matching overhead when responses come back. There is no magic number in some protocols like memcache, redis, it is hard to distinguish them in the server side, but it is no problem in the client side.
# Support new protocols
brpc is designed to add new protocols at any time, just proceed as follows:
> The protocol that begins with nshead has unified support, just read [this](nshead_service.md).
## add ProtocolType
Add new protocol type in ProtocolType in [options.proto](https://github.com/brpc/brpc/blob/master/src/brpc/options.proto). If you need to add new protocol, please contact us to add it for you to make sure there is no conflict with protocols of others.
Currently we support in ProtocolType(at the end of 2016):
```c++
enum ProtocolType {
PROTOCOL_UNKNOWN = 0;
PROTOCOL_BAIDU_STD = 1;
PROTOCOL_STREAMING_RPC = 2;
PROTOCOL_HULU_PBRPC = 3;
PROTOCOL_SOFA_PBRPC = 4;
PROTOCOL_RTMP = 5;
PROTOCOL_HTTP = 6;
PROTOCOL_PUBLIC_PBRPC = 7;
PROTOCOL_NOVA_PBRPC = 8;
PROTOCOL_NSHEAD_CLIENT = 9; // implemented in brpc-ub
PROTOCOL_NSHEAD = 10;
PROTOCOL_HADOOP_RPC = 11;
PROTOCOL_HADOOP_SERVER_RPC = 12;
PROTOCOL_MONGO = 13; // server side only
PROTOCOL_UBRPC_COMPACK = 14;
PROTOCOL_DIDX_CLIENT = 15; // Client side only
PROTOCOL_REDIS = 16; // Client side only
PROTOCOL_MEMCACHE = 17; // Client side only
PROTOCOL_ITP = 18;
PROTOCOL_NSHEAD_MCPACK = 19;
PROTOCOL_DISP_IDL = 20; // Client side only
PROTOCOL_ERSDA_CLIENT = 21; // Client side only
PROTOCOL_UBRPC_MCPACK2 = 22; // Client side only
}
```
## Implement Callbacks
All callbacks are defined in struct Protocol, which is defined in [protocol.h](https://github.com/brpc/brpc/blob/master/src/brpc/protocol.h). Among all these callbacks, `parse` is a callback that must be implmented. Besides, `process_request` must be implemented in the server side and `serialize_request`, `pack_request`, `process_response` must be implemented in the client side.
It is difficult to implement callbacks of the protocol. These codes is not like the codes that ordinary users use which has good prompts and protections. You have to figure it out how to handle similar code in other protocols and implement your own protocol, then send it to us to do code review.
### parse
```c++
typedef ParseResult (*Parse)(butil::IOBuf* source, Socket *socket, bool read_eof, const void *arg);
```
用于把消息从source上切割下来,client端和server端使用同一个parse函数。返回的消息会被递给process_request(server端)或process_response(client端)。
参数:source是读取到的二进制内容,socket是对应的连接,read_eof为true表示连接已被对端关闭,arg在server端是对应server的指针,在client端是NULL。
ParseResult可能是错误,也可能包含一个切割下来的message,可能的值有:
- PARSE_ERROR_TRY_OTHERS :不是这个协议,框架会尝试下一个协议。source不能被消费。
- PARSE_ERROR_NOT_ENOUGH_DATA : 到目前为止数据内容不违反协议,但不构成完整的消息。等到连接上有新数据时,新数据会被append入source并重新调用parse。如果不确定数据是否一定属于这个协议,source不应被消费,如果确定数据属于这个协议,也可以把source的内容转移到内部的状态中去。比如http协议解析中即使source不包含一个完整的http消息,它也会被http parser消费掉,以避免下一次重复解析。
- PARSE_ERROR_TOO_BIG_DATA : 消息太大,拒绝掉以保护server,连接会被关闭。
- PARSE_ERROR_NO_RESOURCE : 内部错误,比如资源分配失败。连接会被关闭。
- PARSE_ERROR_ABSOLUTELY_WRONG : 应该是这个协议(比如magic number匹配了),但是格式不符合预期。连接会被关闭。
### serialize_request
```c++
typedef bool (*SerializeRequest)(butil::IOBuf* request_buf,
Controller* cntl,
const google::protobuf::Message* request);
```
把request序列化进request_buf,client端必须实现。发生在pack_request之前,一次RPC中只会调用一次。cntl包含某些协议(比如http)需要的信息。成功返回true,否则false。
### pack_request
```c++
typedef int (*PackRequest)(butil::IOBuf* msg,
uint64_t correlation_id,
const google::protobuf::MethodDescriptor* method,
Controller* controller,
const butil::IOBuf& request_buf,
const Authenticator* auth);
```
把request_buf打包入msg,每次向server发送消息前(包括重试)都会调用。当auth不为空时,需要打包认证信息。成功返回0,否则-1。
### process_request
```c++
typedef void (*ProcessRequest)(InputMessageBase* msg_base);
```
处理server端parse返回的消息,server端必须实现。可能会在和parse()不同的线程中运行。多个process_request可能同时运行。
在r34386后必须在处理结束时调用msg_base->Destroy(),为了防止漏调,考虑使用DestroyingPtr<>
### process_response
```c++
typedef void (*ProcessResponse)(InputMessageBase* msg);
```
处理client端parse返回的消息,client端必须实现。可能会在和parse()不同的线程中运行。多个process_response可能同时运行。
在r34386后必须在处理结束时调用msg_base->Destroy(),为了防止漏调,考虑使用DestroyingPtr<>
### verify
```c++
typedef bool (*Verify)(const InputMessageBase* msg);
```
处理连接的认证,只会对连接上的第一个消息调用,需要支持认证的server端必须实现,不需要认证或仅支持client端的协议可填NULL。成功返回true,否则false。
### parse_server_address
```c++
typedef bool (*ParseServerAddress)(butil::EndPoint* out, const char* server_addr_and_port);
```
把server_addr_and_port(Channel.Init的一个参数)转化为butil::EndPoint,可选。一些协议对server地址的表达和理解可能是不同的。
### get_method_name
```c++
typedef const std::string& (*GetMethodName)(const google::protobuf::MethodDescriptor* method,
const Controller*);
```
定制method name,可选。
### supported_connection_type
标记支持的连接方式。如果支持所有连接方式,设为CONNECTION_TYPE_ALL。如果只支持连接池和短连接,设为CONNECTION_TYPE_POOLED_AND_SHORT。
### name
协议的名称,会出现在各种配置和显示中,越简短越好,必须是字符串常量。
## 注册到全局
实现好的协议要调用RegisterProtocol[注册到全局](https://github.com/brpc/brpc/blob/master/src/brpc/global.cpp),以便brpc发现。就像这样:
```c++
Protocol http_protocol = { ParseHttpMessage,
SerializeHttpRequest, PackHttpRequest,
ProcessHttpRequest, ProcessHttpResponse,
VerifyHttpRequest, ParseHttpServerAddress,
GetHttpMethodName,
CONNECTION_TYPE_POOLED_AND_SHORT,
"http" };
if (RegisterProtocol(PROTOCOL_HTTP, http_protocol) != 0) {
exit(1);
}
```
This diff is collapsed.
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/allocator/type_profiler_control.h"
namespace butil {
namespace type_profiler {
namespace {
#if defined(TYPE_PROFILING)
const bool kTypeProfilingEnabled = true;
#else
const bool kTypeProfilingEnabled = false;
#endif
bool g_enable_intercept = kTypeProfilingEnabled;
} // namespace
// static
void Controller::Stop() {
g_enable_intercept = false;
}
// static
bool Controller::IsProfiling() {
return kTypeProfilingEnabled && g_enable_intercept;
}
// static
void Controller::Restart() {
g_enable_intercept = kTypeProfilingEnabled;
}
} // namespace type_profiler
} // namespace butil
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
#include "butil/gtest_prod_util.h"
namespace butil {
namespace type_profiler {
class Controller {
public:
static void Stop();
static bool IsProfiling();
private:
FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest,
TestProfileNewWithoutProfiledDelete);
// It must be used only from allowed unit tests. The following is only
// allowed for use in unit tests. Profiling should never be restarted in
// regular use.
static void Restart();
};
} // namespace type_profiler
} // namespace butil
#endif // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
......@@ -7,8 +7,6 @@
#include <stddef.h>
#include <ostream>
#include "butil/bind.h"
#include "butil/callback.h"
#include "butil/logging.h"
namespace butil {
......@@ -44,18 +42,13 @@ AtExitManager::~AtExitManager() {
// static
void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
DCHECK(func);
RegisterTask(butil::Bind(func, param));
}
// static
void AtExitManager::RegisterTask(butil::Closure task) {
if (!g_top_manager) {
NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
return;
}
AutoLock lock(g_top_manager->lock_);
g_top_manager->stack_.push(task);
g_top_manager->stack_.push({func, param});
}
// static
......@@ -68,8 +61,8 @@ void AtExitManager::ProcessCallbacksNow() {
AutoLock lock(g_top_manager->lock_);
while (!g_top_manager->stack_.empty()) {
butil::Closure task = g_top_manager->stack_.top();
task.Run();
Callback task = g_top_manager->stack_.top();
task.func(task.param);
g_top_manager->stack_.pop();
}
}
......
......@@ -9,7 +9,6 @@
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/synchronization/lock.h"
namespace butil {
......@@ -42,9 +41,6 @@ class BASE_EXPORT AtExitManager {
// the callback function is void func(void*).
static void RegisterCallback(AtExitCallbackType func, void* param);
// Registers the specified task to be called at exit.
static void RegisterTask(butil::Closure task);
// Calls the functions registered with RegisterCallback in LIFO order. It
// is possible to register new callbacks after calling this function.
static void ProcessCallbacksNow();
......@@ -57,8 +53,12 @@ class BASE_EXPORT AtExitManager {
explicit AtExitManager(bool shadow);
private:
struct Callback {
AtExitCallbackType func;
void* param;
};
butil::Lock lock_;
std::stack<butil::Closure> stack_;
std::stack<Callback> stack_;
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
DISALLOW_COPY_AND_ASSIGN(AtExitManager);
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/barrier_closure.h"
#include "butil/atomic_ref_count.h"
#include "butil/bind.h"
namespace {
// Maintains state for a BarrierClosure.
class BarrierInfo {
public:
BarrierInfo(int num_callbacks_left, const butil::Closure& done_closure);
void Run();
private:
butil::AtomicRefCount num_callbacks_left_;
butil::Closure done_closure_;
};
BarrierInfo::BarrierInfo(int num_callbacks, const butil::Closure& done_closure)
: num_callbacks_left_(num_callbacks),
done_closure_(done_closure) {
}
void BarrierInfo::Run() {
DCHECK(!butil::AtomicRefCountIsZero(&num_callbacks_left_));
if (!butil::AtomicRefCountDec(&num_callbacks_left_)) {
done_closure_.Run();
done_closure_.Reset();
}
}
} // namespace
namespace butil {
butil::Closure BarrierClosure(int num_callbacks_left,
const butil::Closure& done_closure) {
DCHECK(num_callbacks_left >= 0);
if (num_callbacks_left == 0)
done_closure.Run();
return butil::Bind(&BarrierInfo::Run,
butil::Owned(
new BarrierInfo(num_callbacks_left, done_closure)));
}
} // namespace butil
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BARRIER_CLOSURE_H_
#define BASE_BARRIER_CLOSURE_H_
#include "butil/base_export.h"
#include "butil/callback_forward.h"
namespace butil {
// BarrierClosure executes |done_closure| after it has been invoked
// |num_closures| times.
//
// If |num_closures| is 0, |done_closure| is executed immediately.
//
// BarrierClosure is thread-safe - the count of remaining closures is
// maintained as a butil::AtomicRefCount. |done_closure| will be run on
// the thread that calls the final Run() on the returned closures.
//
// |done_closure| is also Reset() on the final calling thread but due to the
// refcounted nature of callbacks, it is hard to know what thread resources
// will be released on.
BASE_EXPORT butil::Closure BarrierClosure(int num_closures,
const butil::Closure& done_closure);
} // namespace butil
#endif // BASE_BARRIER_CLOSURE_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BASE_PATHS_H_
#define BASE_BASE_PATHS_H_
// This file declares path keys for the base module. These can be used with
// the PathService to access various special directories and files.
#include "butil/build_config.h"
#if defined(OS_WIN)
#include "butil/base_paths_win.h"
#elif defined(OS_MACOSX)
#include "butil/base_paths_mac.h"
#elif defined(OS_ANDROID)
#include "butil/base_paths_android.h"
#endif
#if defined(OS_POSIX)
#include "butil/base_paths_posix.h"
#endif
namespace butil {
enum BasePathKey {
PATH_START = 0,
DIR_CURRENT, // Current directory.
DIR_EXE, // Directory containing FILE_EXE.
DIR_MODULE, // Directory containing FILE_MODULE.
DIR_TEMP, // Temporary directory.
DIR_HOME, // User's root home directory. On Windows this will look
// like "C:\Users\you" (or on XP
// "C:\Document and Settings\you") which isn't necessarily
// a great place to put files.
FILE_EXE, // Path and filename of the current executable.
FILE_MODULE, // Path and filename of the module containing the code for
// the PathService (which could differ from FILE_EXE if the
// PathService were compiled into a shared object, for
// example).
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
// for tests that need to locate various resources. It
// should not be used outside of test code.
DIR_USER_DESKTOP, // The current user's Desktop.
DIR_TEST_DATA, // Used only for testing.
PATH_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BASE_PATHS_ANDROID_H_
#define BASE_BASE_PATHS_ANDROID_H_
// This file declares Android-specific path keys for the base module.
// These can be used with the PathService to access various special
// directories and files.
namespace butil {
enum {
PATH_ANDROID_START = 300,
DIR_ANDROID_APP_DATA, // Directory where to put Android app's data.
DIR_ANDROID_EXTERNAL_STORAGE, // Android external storage directory.
PATH_ANDROID_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_ANDROID_H_
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BASE_PATHS_MAC_H_
#define BASE_BASE_PATHS_MAC_H_
// This file declares Mac-specific path keys for the base module.
// These can be used with the PathService to access various special
// directories and files.
namespace butil {
enum {
PATH_MAC_START = 200,
DIR_APP_DATA, // ~/Library/Application Support
PATH_MAC_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_MAC_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
// in base/path_service.cc.
#include <dlfcn.h>
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#include "base/base_paths.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/build_config.h"
namespace {
void GetNSExecutablePath(base::FilePath* path) {
DCHECK(path);
// Executable path can have relative references ("..") depending on
// how the app was launched.
uint32_t executable_length = 0;
_NSGetExecutablePath(NULL, &executable_length);
DCHECK_GT(executable_length, 1u);
std::string executable_path;
int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
&executable_length);
DCHECK_EQ(rv, 0);
// _NSGetExecutablePath may return paths containing ./ or ../ which makes
// FilePath::DirName() work incorrectly, convert it to absolute path so that
// paths such as DIR_SOURCE_ROOT can work, since we expect absolute paths to
// be returned here.
*path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
}
// Returns true if the module for |address| is found. |path| will contain
// the path to the module. Note that |path| may not be absolute.
bool GetModulePathForAddress(base::FilePath* path,
const void* address) WARN_UNUSED_RESULT;
bool GetModulePathForAddress(base::FilePath* path, const void* address) {
Dl_info info;
if (dladdr(address, &info) == 0)
return false;
*path = base::FilePath(info.dli_fname);
return true;
}
} // namespace
namespace base {
bool PathProviderMac(int key, base::FilePath* result) {
switch (key) {
case base::FILE_EXE:
GetNSExecutablePath(result);
return true;
case base::FILE_MODULE:
return GetModulePathForAddress(result,
reinterpret_cast<const void*>(&base::PathProviderMac));
case base::DIR_APP_DATA: {
bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
result);
#if defined(OS_IOS)
// On IOS, this directory does not exist unless it is created explicitly.
if (success && !base::PathExists(*result))
success = base::CreateDirectory(*result);
#endif // defined(OS_IOS)
return success;
}
case base::DIR_SOURCE_ROOT:
// Go through PathService to catch overrides.
if (!PathService::Get(base::FILE_EXE, result))
return false;
// Start with the executable's directory.
*result = result->DirName();
#if !defined(OS_IOS)
if (base::mac::AmIBundled()) {
// The bundled app executables (Chromium, TestShell, etc) live five
// levels down, eg:
// src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
*result = result->DirName().DirName().DirName().DirName().DirName();
} else {
// Unit tests execute two levels deep from the source root, eg:
// src/xcodebuild/{Debug|Release}/base_unittests
*result = result->DirName().DirName();
}
#endif
return true;
case base::DIR_USER_DESKTOP:
#if defined(OS_IOS)
// iOS does not have desktop directories.
NOTIMPLEMENTED();
return false;
#else
return base::mac::GetUserDirectory(NSDesktopDirectory, result);
#endif
case base::DIR_CACHE:
return base::mac::GetUserDirectory(NSCachesDirectory, result);
default:
return false;
}
}
} // namespace base
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Defines butil::PathProviderPosix, default path provider on POSIX OSes that
// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and
// Android).
#include <ostream>
#include <string>
#include "butil/base_paths.h"
#include "butil/environment.h"
#include "butil/file_util.h"
#include "butil/files/file_path.h"
#include "butil/logging.h"
#include "butil/memory/scoped_ptr.h"
#include "butil/nix/xdg_util.h"
#include "butil/path_service.h"
#include "butil/process/process_metrics.h"
#include "butil/build_config.h"
#if defined(OS_FREEBSD)
#include <sys/param.h>
#include <sys/sysctl.h>
#elif defined(OS_SOLARIS)
#include <stdlib.h>
#endif
namespace butil {
bool PathProviderPosix(int key, FilePath* result) {
FilePath path;
switch (key) {
case butil::FILE_EXE:
case butil::FILE_MODULE: { // TODO(evanm): is this correct?
#if defined(OS_LINUX)
FilePath bin_dir;
if (!ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) {
NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
return false;
}
*result = bin_dir;
return true;
#elif defined(OS_FREEBSD)
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
char bin_dir[PATH_MAX + 1];
size_t length = sizeof(bin_dir);
// Upon return, |length| is the number of bytes written to |bin_dir|
// including the string terminator.
int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
if (error < 0 || length <= 1) {
NOTREACHED() << "Unable to resolve path.";
return false;
}
*result = FilePath(FilePath::StringType(bin_dir, length - 1));
return true;
#elif defined(OS_SOLARIS)
char bin_dir[PATH_MAX + 1];
if (realpath(getexecname(), bin_dir) == NULL) {
NOTREACHED() << "Unable to resolve " << getexecname() << ".";
return false;
}
*result = FilePath(bin_dir);
return true;
#elif defined(OS_OPENBSD)
// There is currently no way to get the executable path on OpenBSD
char* cpath;
if ((cpath = getenv("CHROME_EXE_PATH")) != NULL)
*result = FilePath(cpath);
else
*result = FilePath("/usr/local/chrome/chrome");
return true;
#endif
}
case butil::DIR_SOURCE_ROOT: {
// Allow passing this in the environment, for more flexibility in build
// tree configurations (sub-project builds, gyp --output_dir, etc.)
scoped_ptr<butil::Environment> env(butil::Environment::Create());
std::string cr_source_root;
if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) {
path = FilePath(cr_source_root);
if (butil::PathExists(path)) {
*result = path;
return true;
} else {
DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
<< "point to a directory.";
}
}
// On POSIX, unit tests execute two levels deep from the source root.
// For example: out/{Debug|Release}/net_unittest
if (PathService::Get(butil::DIR_EXE, &path)) {
*result = path.DirName().DirName();
return true;
}
DLOG(ERROR) << "Couldn't find your source root. "
<< "Try running from your chromium/src directory.";
return false;
}
case butil::DIR_USER_DESKTOP:
*result = butil::nix::GetXDGUserDirectory("DESKTOP", "Desktop");
return true;
case butil::DIR_CACHE: {
scoped_ptr<butil::Environment> env(butil::Environment::Create());
FilePath cache_dir(butil::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
".cache"));
*result = cache_dir;
return true;
}
}
return false;
}
} // namespace butil
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_BASE_PATHS_POSIX_H_
#define BASE_BASE_PATHS_POSIX_H_
// This file declares windows-specific path keys for the base module.
// These can be used with the PathService to access various special
// directories and files.
namespace butil {
enum {
PATH_POSIX_START = 400,
DIR_CACHE, // Directory where to put cache data. Note this is
// *not* where the browser cache lives, but the
// browser cache can be a subdirectory.
// This is $XDG_CACHE_HOME on Linux and
// ~/Library/Caches on Mac.
PATH_POSIX_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_POSIX_H_
This diff is collapsed.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/bind_helpers.h"
#include "butil/callback.h"
namespace butil {
void DoNothing() {
}
} // namespace butil
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CALLBACK_FORWARD_H_
#define BASE_CALLBACK_FORWARD_H_
namespace butil {
template <typename Sig>
class Callback;
typedef Callback<void(void)> Closure;
} // namespace butil
#endif // BASE_CALLBACK_FORWARD_H
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/callback_helpers.h"
#include "butil/callback.h"
namespace butil {
ScopedClosureRunner::ScopedClosureRunner() {
}
ScopedClosureRunner::ScopedClosureRunner(const Closure& closure)
: closure_(closure) {
}
ScopedClosureRunner::~ScopedClosureRunner() {
if (!closure_.is_null())
closure_.Run();
}
void ScopedClosureRunner::Reset() {
Closure old_closure = Release();
if (!old_closure.is_null())
old_closure.Run();
}
void ScopedClosureRunner::Reset(const Closure& closure) {
Closure old_closure = Release();
closure_ = closure;
if (!old_closure.is_null())
old_closure.Run();
}
Closure ScopedClosureRunner::Release() {
Closure result = closure_;
closure_.Reset();
return result;
}
} // namespace butil
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This defines helpful methods for dealing with Callbacks. Because Callbacks
// are implemented using templates, with a class per callback signature, adding
// methods to Callback<> itself is unattractive (lots of extra code gets
// generated). Instead, consider adding methods here.
//
// ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a
// copy) after the original callback is Reset(). This can be handy if Run()
// reads/writes the variable holding the Callback.
#ifndef BASE_CALLBACK_HELPERS_H_
#define BASE_CALLBACK_HELPERS_H_
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/compiler_specific.h"
namespace butil {
template <typename Sig>
butil::Callback<Sig> ResetAndReturn(butil::Callback<Sig>* cb) {
butil::Callback<Sig> ret(*cb);
cb->Reset();
return ret;
}
// ScopedClosureRunner is akin to scoped_ptr for Closures. It ensures that the
// Closure is executed and deleted no matter how the current scope exits.
class BASE_EXPORT ScopedClosureRunner {
public:
ScopedClosureRunner();
explicit ScopedClosureRunner(const Closure& closure);
~ScopedClosureRunner();
void Reset();
void Reset(const Closure& closure);
Closure Release() WARN_UNUSED_RESULT;
private:
Closure closure_;
DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner);
};
} // namespace butil
#endif // BASE_CALLBACK_HELPERS_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/callback_internal.h"
#include "butil/logging.h"
namespace butil {
namespace internal {
bool CallbackBase::is_null() const {
return bind_state_.get() == NULL;
}
void CallbackBase::Reset() {
polymorphic_invoke_ = NULL;
// NULL the bind_state_ last, since it may be holding the last ref to whatever
// object owns us, and we may be deleted after that.
bind_state_ = NULL;
}
bool CallbackBase::Equals(const CallbackBase& other) const {
return bind_state_.get() == other.bind_state_.get() &&
polymorphic_invoke_ == other.polymorphic_invoke_;
}
CallbackBase::CallbackBase(BindStateBase* bind_state)
: bind_state_(bind_state),
polymorphic_invoke_(NULL) {
DCHECK(!bind_state_.get() || bind_state_->HasOneRef());
}
CallbackBase::~CallbackBase() {
}
} // namespace internal
} // namespace butil
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains utility functions and classes that help the
// implementation, and management of the Callback objects.
#ifndef BASE_CALLBACK_INTERNAL_H_
#define BASE_CALLBACK_INTERNAL_H_
#include <stddef.h>
#include "butil/base_export.h"
#include "butil/memory/ref_counted.h"
#include "butil/memory/scoped_ptr.h"
template <typename T>
class ScopedVector;
namespace butil {
namespace internal {
// BindStateBase is used to provide an opaque handle that the Callback
// class can use to represent a function object with bound arguments. It
// behaves as an existential type that is used by a corresponding
// DoInvoke function to perform the function execution. This allows
// us to shield the Callback class from the types of the bound argument via
// "type erasure."
class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
protected:
friend class RefCountedThreadSafe<BindStateBase>;
virtual ~BindStateBase() {}
};
// Holds the Callback methods that don't require specialization to reduce
// template bloat.
class BASE_EXPORT CallbackBase {
public:
// Returns true if Callback is null (doesn't refer to anything).
bool is_null() const;
// Returns the Callback into an uninitialized state.
void Reset();
protected:
// In C++, it is safe to cast function pointers to function pointers of
// another type. It is not okay to use void*. We create a InvokeFuncStorage
// that that can store our function pointer, and then cast it back to
// the original type on usage.
typedef void(*InvokeFuncStorage)(void);
// Returns true if this callback equals |other|. |other| may be null.
bool Equals(const CallbackBase& other) const;
// Allow initializing of |bind_state_| via the constructor to avoid default
// initialization of the scoped_refptr. We do not also initialize
// |polymorphic_invoke_| here because doing a normal assignment in the
// derived Callback templates makes for much nicer compiler errors.
explicit CallbackBase(BindStateBase* bind_state);
// Force the destructor to be instantiated inside this translation unit so
// that our subclasses will not get inlined versions. Avoids more template
// bloat.
~CallbackBase();
scoped_refptr<BindStateBase> bind_state_;
InvokeFuncStorage polymorphic_invoke_;
};
// A helper template to determine if given type is non-const move-only-type,
// i.e. if a value of the given type should be passed via .Pass() in a
// destructive way.
template <typename T> struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
template <typename U>
static NoType Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) &&
!is_const<T>::value;
};
// This is a typetraits object that's used to take an argument type, and
// extract a suitable type for storing and forwarding arguments.
//
// In particular, it strips off references, and converts arrays to
// pointers for storage; and it avoids accidentally trying to create a
// "reference of a reference" if the argument is a reference type.
//
// This array type becomes an issue for storage because we are passing bound
// parameters by const reference. In this case, we end up passing an actual
// array type in the initializer list which C++ does not allow. This will
// break passing of C-string literals.
template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
struct CallbackParamTraits {
typedef const T& ForwardType;
typedef T StorageType;
};
// The Storage should almost be impossible to trigger unless someone manually
// specifies type of the bind parameters. However, in case they do,
// this will guard against us accidentally storing a reference parameter.
//
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraits<T&, false> {
typedef T& ForwardType;
typedef T StorageType;
};
// Note that for array types, we implicitly add a const in the conversion. This
// means that it is not possible to bind array arguments to functions that take
// a non-const pointer. Trying to specialize the template based on a "const
// T[n]" does not seem to match correctly, so we are stuck with this
// restriction.
template <typename T, size_t n>
struct CallbackParamTraits<T[n], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraits<T[], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// Parameter traits for movable-but-not-copyable scopers.
//
// Callback<>/Bind() understands movable-but-not-copyable semantics where
// the type cannot be copied but can still have its state destructively
// transferred (aka. moved) to another instance of the same type by calling a
// helper function. When used with Bind(), this signifies transferal of the
// object's state to the target function.
//
// For these types, the ForwardType must not be a const reference, or a
// reference. A const reference is inappropriate, and would break const
// correctness, because we are implementing a destructive move. A non-const
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
struct CallbackParamTraits<T, true> {
typedef T ForwardType;
typedef T StorageType;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
// used by the Callback/Bind system for a set of movable-but-not-copyable
// types. It is needed because forwarding a movable-but-not-copyable
// argument to another function requires us to invoke the proper move
// operator to create a rvalue version of the type. The supported types are
// whitelisted below as overloads of the CallbackForward() function. The
// default template compiles out to be a no-op.
//
// In C++11, std::forward would replace all uses of this function. However, it
// is impossible to implement a general std::forward with C++11 due to a lack
// of rvalue references.
//
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
// simulate std::forward() and forward the result of one Callback as a
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
return t;
}
template <typename T>
typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
return t.Pass();
}
} // namespace internal
} // namespace butil
#endif // BASE_CALLBACK_INTERNAL_H_
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This class works with command lines: building and parsing.
// Arguments with prefixes ('--', '-', and on Windows, '/') are switches.
// Switches will precede all other arguments without switch prefixes.
// Switches can optionally have values, delimited by '=', e.g., "-switch=value".
// An argument of "--" will terminate switch parsing during initialization,
// interpreting subsequent tokens as non-switch arguments, regardless of prefix.
// There is a singleton read-only CommandLine that represents the command line
// that the current process was started with. It must be initialized in main().
#ifndef BASE_COMMAND_LINE_H_
#define BASE_COMMAND_LINE_H_
#include <stddef.h>
#include <map>
#include <string>
#include <vector>
#include "butil/base_export.h"
#include "butil/build_config.h"
namespace butil {
class FilePath;
class BASE_EXPORT CommandLine {
public:
#if defined(OS_WIN)
// The native command line string type.
typedef std::wstring StringType;
#elif defined(OS_POSIX)
typedef std::string StringType;
#endif
typedef StringType::value_type CharType;
typedef std::vector<StringType> StringVector;
typedef std::map<std::string, StringType> SwitchMap;
// A constructor for CommandLines that only carry switches and arguments.
enum NoProgram { NO_PROGRAM };
explicit CommandLine(NoProgram no_program);
// Construct a new command line with |program| as argv[0].
explicit CommandLine(const FilePath& program);
// Construct a new command line from an argument list.
CommandLine(int argc, const CharType* const* argv);
explicit CommandLine(const StringVector& argv);
~CommandLine();
#if defined(OS_WIN)
// By default this class will treat command-line arguments beginning with
// slashes as switches on Windows, but not other platforms.
//
// If this behavior is inappropriate for your application, you can call this
// function BEFORE initializing the current process' global command line
// object and the behavior will be the same as Posix systems (only hyphens
// begin switches, everything else will be an arg).
static void set_slash_is_not_a_switch();
#endif
// Initialize the current process CommandLine singleton. On Windows, ignores
// its arguments (we instead parse GetCommandLineW() directly) because we
// don't trust the CRT's parsing of the command line, but it still must be
// called to set up the command line. Returns false if initialization has
// already occurred, and true otherwise. Only the caller receiving a 'true'
// return value should take responsibility for calling Reset.
static bool Init(int argc, const char* const* argv);
// Destroys the current process CommandLine singleton. This is necessary if
// you want to reset the base library to its initial state (for example, in an
// outer library that needs to be able to terminate, and be re-initialized).
// If Init is called only once, as in main(), Reset() is not necessary.
static void Reset();
// Get the singleton CommandLine representing the current process's
// command line. Note: returned value is mutable, but not thread safe;
// only mutate if you know what you're doing!
static CommandLine* ForCurrentProcess();
// Returns true if the CommandLine has been initialized for the given process.
static bool InitializedForCurrentProcess();
#if defined(OS_WIN)
static CommandLine FromString(const std::wstring& command_line);
#endif
// Initialize from an argv vector.
void InitFromArgv(int argc, const CharType* const* argv);
void InitFromArgv(const StringVector& argv);
// Constructs and returns the represented command line string.
// CAUTION! This should be avoided on POSIX because quoting behavior is
// unclear.
StringType GetCommandLineString() const;
// Constructs and returns the represented arguments string.
// CAUTION! This should be avoided on POSIX because quoting behavior is
// unclear.
StringType GetArgumentsString() const;
// Returns the original command line string as a vector of strings.
const StringVector& argv() const { return argv_; }
// Get and Set the program part of the command line string (the first item).
FilePath GetProgram() const;
void SetProgram(const FilePath& program);
// Returns true if this command line contains the given switch.
// (Switch names are case-insensitive).
bool HasSwitch(const std::string& switch_string) const;
// Returns the value associated with the given switch. If the switch has no
// value or isn't present, this method returns the empty string.
std::string GetSwitchValueASCII(const std::string& switch_string) const;
FilePath GetSwitchValuePath(const std::string& switch_string) const;
StringType GetSwitchValueNative(const std::string& switch_string) const;
// Get a copy of all switches, along with their values.
const SwitchMap& GetSwitches() const { return switches_; }
// Append a switch [with optional value] to the command line.
// Note: Switches will precede arguments regardless of appending order.
void AppendSwitch(const std::string& switch_string);
void AppendSwitchPath(const std::string& switch_string,
const FilePath& path);
void AppendSwitchNative(const std::string& switch_string,
const StringType& value);
void AppendSwitchASCII(const std::string& switch_string,
const std::string& value);
// Copy a set of switches (and any values) from another command line.
// Commonly used when launching a subprocess.
void CopySwitchesFrom(const CommandLine& source,
const char* const switches[],
size_t count);
// Get the remaining arguments to the command.
StringVector GetArgs() const;
// Append an argument to the command line. Note that the argument is quoted
// properly such that it is interpreted as one argument to the target command.
// AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8.
// Note: Switches will precede arguments regardless of appending order.
void AppendArg(const std::string& value);
void AppendArgPath(const FilePath& value);
void AppendArgNative(const StringType& value);
// Append the switches and arguments from another command line to this one.
// If |include_program| is true, include |other|'s program as well.
void AppendArguments(const CommandLine& other, bool include_program);
// Insert a command before the current command.
// Common for debuggers, like "valgrind" or "gdb --args".
void PrependWrapper(const StringType& wrapper);
#if defined(OS_WIN)
// Initialize by parsing the given command line string.
// The program name is assumed to be the first item in the string.
void ParseFromString(const std::wstring& command_line);
#endif
private:
// Disallow default constructor; a program name must be explicitly specified.
CommandLine();
// Allow the copy constructor. A common pattern is to copy of the current
// process's command line and then add some flags to it. For example:
// CommandLine cl(*CommandLine::ForCurrentProcess());
// cl.AppendSwitch(...);
// The singleton CommandLine representing the current process's command line.
static CommandLine* current_process_commandline_;
// The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* }
StringVector argv_;
// Parsed-out switch keys and values.
SwitchMap switches_;
// The index after the program and switches, any arguments start here.
size_t begin_args_;
};
} // namespace butil
// TODO(brettw) remove once all callers specify the namespace properly.
using butil::CommandLine;
#endif // BASE_COMMAND_LINE_H_
......@@ -43,7 +43,6 @@
#include "butil/strings/stringprintf.h"
#include "butil/strings/sys_string_conversions.h"
#include "butil/strings/utf_string_conversions.h"
#include "butil/sys_info.h"
#include "butil/threading/thread_restrictions.h"
#include "butil/time/time.h"
......
......@@ -60,7 +60,6 @@ typedef pthread_mutex_t* MutexHandle;
#include <string>
#include "butil/file_util.h"
#include "butil/command_line.h"
#include "butil/debug/alias.h"
#include "butil/debug/debugger.h"
#include "butil/debug/stack_trace.h"
......
......@@ -7,7 +7,6 @@
#include "butil/memory/ref_counted.h"
#include "butil/type_traits.h"
#include "butil/tuple.h"
#include "butil/build_config.h"
// It is dangerous to post a task with a T* argument where T is a subtype of
......
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/nix/mime_util_xdg.h"
#include "butil/files/file_path.h"
#include "butil/lazy_instance.h"
#include "butil/synchronization/lock.h"
#include "butil/third_party/xdg_mime/xdgmime.h"
#include "butil/threading/thread_restrictions.h"
namespace butil {
namespace nix {
namespace {
// None of the XDG stuff is thread-safe, so serialize all access under
// this lock.
LazyInstance<Lock>::Leaky g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER;
} // namespace
std::string GetFileMimeType(const FilePath& filepath) {
if (filepath.empty())
return std::string();
ThreadRestrictions::AssertIOAllowed();
AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str());
}
std::string GetDataMimeType(const std::string& data) {
ThreadRestrictions::AssertIOAllowed();
AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL);
}
} // namespace nix
} // namespace butil
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_NIX_MIME_UTIL_XDG_H_
#define BASE_NIX_MIME_UTIL_XDG_H_
#include <string>
#include "butil/base_export.h"
#include "butil/build_config.h"
namespace butil {
class FilePath;
namespace nix {
// Gets the mime type for a file based on its filename. The file path does not
// have to exist. Please note because it doesn't touch the disk, this does not
// work for directories.
// If the mime type is unknown, this will return application/octet-stream.
BASE_EXPORT std::string GetFileMimeType(const FilePath& filepath);
// Get the mime type for a byte vector.
BASE_EXPORT std::string GetDataMimeType(const std::string& data);
} // namespace nix
} // namespace butil
#endif // BASE_NIX_MIME_UTIL_XDG_H_
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/process/kill.h"
#include "butil/process/process_iterator.h"
namespace butil {
bool KillProcesses(const FilePath::StringType& executable_name,
int exit_code,
const ProcessFilter* filter) {
bool result = true;
NamedProcessIterator iter(executable_name, filter);
while (const ProcessEntry* entry = iter.NextProcessEntry()) {
#if defined(OS_WIN)
result &= KillProcessById(entry->pid(), exit_code, true);
#else
result &= KillProcess(entry->pid(), exit_code, true);
#endif
}
return result;
}
} // namespace butil
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "butil/process/memory.h"
namespace butil {
// Defined in memory_mac.mm for Mac.
#if !defined(OS_MACOSX)
bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
const size_t alloc_size = num_items * size;
// Overflow check
if (size && ((alloc_size / size) != num_items)) {
*result = NULL;
return false;
}
if (!UncheckedMalloc(alloc_size, result))
return false;
memset(*result, 0, alloc_size);
return true;
}
#endif
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This module is a simple module that parses the proposed MIME spec listed
at http://freedesktop.org/. It is currently targetted at version 0.12.
There are no formal releases planned for this module, and it is not
intended to be installed at this time. Rather, it is meant to be used
by other libraries or applications to add support for the MIME system.
It is dual-licensed under the terms of the GNU Lesser General Public
License, and the Academic Free License, version 2.0.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment