diff --git a/chapters/beam.asciidoc b/chapters/beam.asciidoc index bad3f39..58f610e 100644 --- a/chapters/beam.asciidoc +++ b/chapters/beam.asciidoc @@ -543,7 +543,7 @@ Note that the star in "+goto+ +*+" does not mean dereference, the expression means jump to an address pointer, we should really write it as "+goto*+". -Now imagine that the compile C code for these instructions end up at +Now imagine that the compiled C code for these instructions end up at memory addresses 0x3000, 0x3100, and 0x3200. When the BEAM code is loaded the three move instructions in the code will be replaced by the memory addresses of the implementation of the instructions. Imagine @@ -576,7 +576,7 @@ BEAM instructions and how they are implemented. Most modern multi-threading operating systems use preemptive scheduling. This means that the operating system decides when to switch from one process to another, regardless of what the process is doing. This protects -the other processes from a processes misbehaving by not yielding in time. +the other processes from a process misbehaving by not yielding in time. In cooperative multitasking which uses a non-preemptive scheduler the running process decides when to yield. This has the advantage that the @@ -599,7 +599,7 @@ stack and heap. On the language level all processes are running concurrently and the programmer should not have to deal with explicit yields. BEAM solves this by keeping track of how long a process has been running. This is -done by counting _reductions_. The term originaly comes from the +done by counting _reductions_. The term originally comes from the mathematical term beta-reduction used in lambda calculus. The definition of a reduction in BEAM is not very specific, but we can diff --git a/chapters/beam_instructions.asciidoc b/chapters/beam_instructions.asciidoc index 4ac77b1..b3a787c 100644 --- a/chapters/beam_instructions.asciidoc +++ b/chapters/beam_instructions.asciidoc @@ -38,7 +38,7 @@ The names and opcodes of the generic instructions are defined in +lib/compiler/src/genop.tab+. The file contains a version number for the Beam instruction format, which -also is wirtten to +.beam+ files. This number has so far never changed +also is written to +.beam+ files. This number has so far never changed and is still at version 0. If the external format would be changed in a non backwards compatible way this number would be changed. @@ -68,7 +68,7 @@ The main content of the file are the opcode definitions of the form: OPNUM: [-]NAME/ARITY ---- Where OPNUM and ARITY are integers, NAME is an identifier starting -with a lowercase letter (a-z), and _:_, _-_, and _/_ are litterals. +with a lowercase letter (a-z), and _:_, _-_, and _/_ are literals. For example: @@ -76,9 +76,9 @@ For example: 1: label/1 ---- -The minus sign (-) indicates a depricated function. A depricated +The minus sign (-) indicates a deprecated function. A deprecated function keeps its opcode in order for the loader to be sort of -backwards compatible (it will recognize depricated instructions and +backwards compatible (it will recognize deprecated instructions and refuse to load the code). In the rest of this Chapter we will go through some BEAM instructions diff --git a/chapters/beam_modules.asciidoc b/chapters/beam_modules.asciidoc index 1626e6b..e918ca6 100644 --- a/chapters/beam_modules.asciidoc +++ b/chapters/beam_modules.asciidoc @@ -293,7 +293,7 @@ parse_chunks([{"StrT", _Size, <>} | Rest], Acc) -> ==== Attributes Chunk -The chunk named `Attr` is optional, but some OTP tools expect the attributes to be present. The releashandler expect the "vsn" attribute to be present. You can get the version attribute from a file with: beam_lib:version(Filename), this function assumes that there is an attribute chunk with a "vsn" attribute present. +The chunk named `Attr` is optional, but some OTP tools expect the attributes to be present. The release handler expects the "vsn" attribute to be present. You can get the version attribute from a file with: beam_lib:version(Filename), this function assumes that there is an attribute chunk with a "vsn" attribute present. The format of the chunk is: @@ -492,7 +492,7 @@ Let's look at the algorithm, used by `beam_asm:encode`. BEAM files use a special TIP: `Beam_asm` is a module in the `compiler` application, part of the Erlang distribution, it is used to assemble binary content of beam modules. -The reason behind this complicated design is to try and fit as much type and value data into the first byte as possible to make code section more compact. After decoding all encoded values become full size machine words or terms. +The reason behind this complicated design is to try and fit as much type and value data into the first byte as possible to make the code section more compact. After decoding, all encoded values become full size machine words or terms. [shaape] ---- @@ -513,7 +513,7 @@ The reason behind this complicated design is to try and fit as much type and val ---- -It uses first 3 bits of a first byte to store the tag which defines the type of the following value. If the bits were all 1 (special value 7 or ?tag_z from `beam_opcodes.hrl`), then few more bits are used. +It uses the first 3 bits of a first byte to store the tag which defines the type of the following value. If the bits were all 1 (special value 7 or ?tag_z from `beam_opcodes.hrl`), then a few more bits are used. For values under 16, the value is placed entirely into bits 4-5-6-7 having bit 3 set to 0: diff --git a/chapters/compiler.asciidoc b/chapters/compiler.asciidoc index 8d309e6..92dc4a0 100644 --- a/chapters/compiler.asciidoc +++ b/chapters/compiler.asciidoc @@ -254,7 +254,7 @@ ok ---- This gives us an +.E+ file, in this case all compiler directives have -been removed and the build in functions +module_info/{1,2}+ have been +been removed and the built in functions +module_info/{1,2}+ have been added to the source: [source,erlang] @@ -361,7 +361,7 @@ that gives you a valid term. E.g.: t() -> [f,?p. ---- -There are few real useages for this other than to win the +There are few real usages for this other than to win the obfuscated Erlang code contest. The main point to remember is that you can not really use the Erlang preprocessor to define a language with a syntax that differs from Erlang. Fortunately there are @@ -411,7 +411,7 @@ To write a parse transform you need to write an Erlang module (lets call it _p_) which exports the function +parse_transform/2+. This function is called by the compiler during the parse transform pass if the module being compiled (lets call it _m_) contains the compiler -option +{parse_transform, p}+. The arguments to the funciton is the +option +{parse_transform, p}+. The arguments to the function is the AST of the module m and the compiler options given to the call to the compiler. diff --git a/chapters/io.asciidoc b/chapters/io.asciidoc index 1ed5b34..52c1775 100644 --- a/chapters/io.asciidoc +++ b/chapters/io.asciidoc @@ -5,13 +5,13 @@ Within Erlang, all communication is done by asynchronous signaling. The communication between an Erlang node and the outside world is done through a _port_. A port is an interface between Erlang processes and an external resource. In early versions of Erlang a port behaved very -much in the same way as a process and you comunicated by sending and +much in the same way as a process and you communicated by sending and receiving signals. You can still communicate with ports this way but there are also a number of BIFs to communicate directly with a port. In this chapter we will look at how ports are used as a common -interface for all IO, how ports comunicate with the outside world and -how Erlang processes comunicate with ports. But first we will look +interface for all IO, how ports communicate with the outside world and +how Erlang processes communicate with ports. But first we will look at how standard IO works on a higher level. === Standard IO === @@ -63,13 +63,13 @@ options: Process P1 has opened a port (Port1) to a file, and is the owner of the port and can receive messages from the port. Process P2 also has a handle to the port and can send messages to the port. The processes -and the port resides in an Erlang node. The file lives in the file and +and the port reside in an Erlang node. The file lives in the file and operating system on the outside of the Erlang node. If the port owner dies or is terminated the port is also killed. When a port terminates all external resources should also be cleaned -up. This is true for all ports that comes with Erlang and if you +up. This is true for all ports that come with Erlang and if you implement your own port you should make sure it does this cleanup. ==== Different types of Ports ==== diff --git a/chapters/scheduling.asciidoc b/chapters/scheduling.asciidoc index bb141b8..31b85f0 100644 --- a/chapters/scheduling.asciidoc +++ b/chapters/scheduling.asciidoc @@ -226,7 +226,7 @@ suspended the field reds is increased by the number of executed reductions. In some C like code something like: `p->reds += (CONTEXT_REDS - p->fcalls)`. -Normally a process would do all its alloted reductions and `fcalls` +Normally a process would do all its allotted reductions and `fcalls` would be 0 at this point, but if the process suspends in a receive waiting for a message it will have some reductions left. @@ -379,7 +379,7 @@ there is one queue per scheduler. ---- The reality is slightly more complicated since Erlang processes have -priorities. Each scheduler actually have three queues. One queue for +priorities. Each scheduler actually has three queues. One queue for _max priority_ tasks, one for _high priority_ tasks and one queue containing both _normal_ and _low priority_ tasks. @@ -394,7 +394,7 @@ containing both _normal_ and _low priority_ tasks. P10 ---- -If there are any processes int the max queue the scheduler will +If there are any processes in the max queue the scheduler will pick these processes for execution. If there are no processes in the max queue but there are processes in the high priority queue the scheduler will pick those processes. Only if there @@ -416,7 +416,7 @@ A processs trying to do a receive on an empty mailbox or on a mailbox with no matching messages will yield and go into the waiting state. -When a message is deliverd to an inbox the sending process will check +When a message is delivered to an inbox the sending process will check whether the receiver is _sleeping_ in the waiting state, and in that case it will _wake_ the process, change its state to runable, and put it at the end of the appropriate ready queue. @@ -425,7 +425,7 @@ If the receive statement has a +timeout+ clause a timer will be created for the process which will trigger after the specified timeout time. The only guarantee the runtime system gives on a timeout is that it will not trigger before the set time, it might be some time after -the intended time before the process is scheduled and get to execute. +the intended time before the process is scheduled and gets to execute. Timers are handled in the VM by a _timing wheel_. That is, an array of time slots which wraps around. Prior to Erlang 18 the timing wheel was @@ -490,7 +490,7 @@ world outside of the Erlang VM. Communications with sockets, pipes, and file IO are all done through ports on the Erlang side. A port, like a process, is created on the same scheduler as the -creating process. Also like processes port uses reductions to decide +creating process. Also like processes ports use reductions to decide when to yield, and they also get to run for 2000 reductions. But since ports don't run Erlang code there are no Erlang function calls to count as reductions, instead each _port task_ is counted as a @@ -644,10 +644,10 @@ schedulers should be allocated to cores. The default behaviour is that it is up to the OS to allocated scheduler threads to cores, but you can also choose to bind schedulers to cores. -The load balancer assumes that there is one schedulers running on each +The load balancer assumes that there is one scheduler running on each core so that moving a process from a overloaded scheduler to an under utilized scheduler will give you more parallel processing power. If -you have changed how schedulers are allocated to cores, or if you OS +you have changed how schedulers are allocated to cores, or if your OS is overloaded or bad at assigning threads to cores, the load balancing might actually work against you. @@ -771,7 +771,7 @@ In the example: Then we are done. In reality things are a bit more complicated since schedulers can be -taken off line. The migration planning is only done for online +taken offline. The migration planning is only done for online schedulers. Also, as mentioned before, this is done per priority level. @@ -781,13 +781,13 @@ run queue of S1 is larger than AMQL and that the run queue of S2 is smaller than the average. This way the migration is only allowed if both queues are still unbalanced. -There are two exception though where a migration is forced even +There are two exceptions though where a migration is forced even when the queues are balanced or even imbalanced in the wrong way. In both these cases a special evacuation flag is set which overrides the balance test. -The evacuation flag is set when a scheduler is taken off line to -ensure that no new processes are scheduled on an off line scheduler. +The evacuation flag is set when a scheduler is taken offline to +ensure that no new processes are scheduled on an offline scheduler. The flag is also set when the scheduler detects that no progress is made on some priority. That is, if there for example is a max priority process which always is ready to run so that no normal priority processes diff --git a/chapters/type_system.asciidoc b/chapters/type_system.asciidoc index 17906ae..8efa59e 100644 --- a/chapters/type_system.asciidoc +++ b/chapters/type_system.asciidoc @@ -200,7 +200,7 @@ word is filled with ones. ==== Tags for Boxed Terms -Erlang terms stored on the heap uses several machine words. Lists, or +Erlang terms stored on the heap use several machine words. Lists, or cons cells, are just two consecutive words on the heap: the head and the tail (or car and cdr as they are called in lisp and some places in the ERTS code).